相关介绍:

 树形结构除了应用于查找和排序等操作时能调高效率,它在信息通讯领域也有着广泛的应用。哈弗曼(Huffman)树就是一种在编码技术方面得到广泛应用的二叉树,它同时也是一种最优二叉树。

哈弗曼树相关的的基本概念:

 为了给出哈弗曼树的定义,从以下几个基本概念出发并进行描述。

  1. 节点间的路径和节点的路径长度:所谓节点间的路径是指一个节点到另一个节点所经历的节点和分支序列。节点的路径长度是指从根节点到该节点间的路径上的分支数目。

  2. 节点的权和节点的带权路径:在实际应用中,人们往往会给树中的每一个节点赋予一个具有某种实际意义的数值,这个数值称为节点的权值。节点的带权路径长度就是该节点的路径长度与该节点的权值的乘积。

  3. 树的带权路径长度:树的带权路径长度就是树中所有叶节点的带权路径长度之和,通常记为:\(WPL=\sum_{i=1}^{n}W_{i} \times L_{i}\)其中,n为叶节点的个数,\(W_{i}\)为第i个叶节点的权值,\(L_{i}\)为第i个叶节点的路径长度

  4. 最优二叉树:给定n个权值并作为n个叶节点按一定规则构造一棵二叉树,使得其带权路径长度达到最小值,则这棵二叉树被称为最优二叉树。下图展示了具有不同带权路径长度的二叉树,其中,第二棵树为最优二叉树

哈弗曼树和哈弗曼编码的构造方法

 哈弗曼树的构造步骤如下所示:

 假设n个叶节点的权值分别为{w1,w2,...,wn},则

  1. 由已知给定的n个权值{w1,w2,w3,...,wn},构造一个由n棵二叉树所构成的森林F={T1,,T2,T3,...,Tn},其中每一棵二叉树只有一个根节点,并且根节点的权值分别为w1,w2,....,wn

  2. 在二叉树森林F中选取根节点的权值最小和次小的两棵二叉树,分别把它们作为左子树和右子树去构造一棵新二叉树,新二叉树的根节点权值为其左、右子树根节点的权值之和

  3. 作为新二叉树的左右子树的两棵二叉树从森林F中删除。将新产生的二叉树加入到森林F中

  4. 重复步骤2和步骤3,直到森林中只剩下一棵二叉树为止,则这棵二叉树就是所构成的哈弗曼树

下图展示了哈弗曼树的构造过程:

哈弗曼树构造过程的代码实现

 以下其代码演示了哈弗曼树的构造实现其中,测试代码所用的图如下所示:

相关代码:

package all_in_tree;

import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue; /**
* 该类用于演示哈弗曼树的构造过程
* @author 学徒
*
*/
public class Huffman
{
//哈弗曼树的根节点
private HuffmanNode root;
//一个优先级队列,确保每次取出的均为节点中其权值最小的节点
private Queue<HuffmanNode> q;
/**
* 用于初始化,其优先队列
*/
public Huffman()
{
Comparator<HuffmanNode> cmp=new Comparator<HuffmanNode>()
{
@Override
public int compare(HuffmanNode obj1,HuffmanNode obj2)
{
int obj1Number=obj1.weight;
int obj2Number=obj2.weight;
if(obj1Number>obj2Number)
return 1;
else if(obj1Number<obj2Number)
return -1;
else
return 0;
}
};
q=new PriorityQueue<HuffmanNode>(11,cmp);
}
/**
* 用于添加节点到优先队列中,进行哈弗曼树的构造
* @param node
*/
public void addHuffmanNode(HuffmanNode node)
{
q.add(node);
}
/**
* 用于构造哈弗曼树
*/
public HuffmanNode createHuffmanTree()
{
while(!q.isEmpty()&&q.size()>=2)
{
HuffmanNode node1=q.poll();
HuffmanNode node2=q.poll();
HuffmanNode newNode=new HuffmanNode();
newNode.weight=node1.weight+node2.weight;
newNode.left=node1;
newNode.right=node2;
q.add(newNode);
}
if(!q.isEmpty())
this.root=q.poll();
return this.root;
}
/**
* 用于测试相关的代码
*/
public static void main(String[] args)
{
Huffman tree=new Huffman();
for(int i=0;i<5;i++)
{
tree.addHuffmanNode(new HuffmanNode((char)('A'+i),i+1));
}
HuffmanNode root=tree.createHuffmanTree();
System.out.println("其最高顶点的权值"+root.weight);
//对该哈弗曼树进行层次遍历
Queue<HuffmanNode> q=new LinkedList<HuffmanNode>();
q.add(root);
while(!q.isEmpty())
{
HuffmanNode node=q.poll();
System.out.print(node.weight+"\t");
if(node.left!=null)
q.add(node.left);
if(node.right!=null)
q.add(node.right);
}
}
}
/**
* 用于创建哈弗曼树的节点类的描述
* @author 学徒
*
*/
class HuffmanNode
{
//用于存放相关的数据
Object data;
//用于记录该节点的权
int weight;
//该节点的左孩子
HuffmanNode left;
//该节点的右孩子
HuffmanNode right;
public HuffmanNode()
{
}
public HuffmanNode(Object data,int weight)
{
this.data=data;
this.weight=weight;
}
} 运行结果: 其最高顶点的权值15
15 6 9 3 3 4 5 1 2

回到目录|·(工)·)

K:哈弗曼树的更多相关文章

  1. HDU2527:Safe Or Unsafe(哈弗曼树)

    Problem Description Javac++ 一天在看计算机的书籍的时候,看到了一个有趣的东西!每一串字符都可以被编码成一些数字来储存信息,但是不同的编码方式得到的储存空间是不一样的!并且当 ...

  2. SLT 优先队列 哈弗曼树最小带权路径

    与普通的队列不同,普通的队列是先进先出的,而优先队列出队的顺序不是先进先出,而是大(或者小)元素先出队,需要#include <queue> 成员函数 成员函数 作用 empty() 判断 ...

  3. java实现哈弗曼树

    O(∩_∩)O~~ 概述 我想学过数据结构的小伙伴一定都认识哈弗曼,这位大神发明了大名鼎鼎的“最优二叉树”,为了纪念他呢,我们称之为“哈弗曼树”.哈弗曼树可以用于哈弗曼编码,编码的话学问可就大了,比如 ...

  4. 哈弗曼树的理解和实现(Java)

    哈弗曼树概述 哈弗曼树又称最优树,是一种带权路径长度最短的树,在实际中有广泛的用途.哈弗曼树的定义,涉及路径.路径长度.权等概念.哈弗曼树可以用于哈弗曼编码,用于压缩,用于密码学等. 哈弗曼树的一些定 ...

  5. PKU 1521 Entropy(简单哈弗曼树_水过)

    题目大意:原题链接 给你一个字符串,首先是计算出一个按正常编码的编码长度,其次是计算出一个用霍夫曼编码的编码长度,最后求正常编码的长度除以霍夫曼编码长度的比值,保留一位小数. 解题思路:需要知道 1. ...

  6. POJ 3253 Fence Repair(简单哈弗曼树_水过)

    题目大意:原题链接 锯木板,锯木板的长度就是花费.比如你要锯成长度为8 5 8的木板,最简单的方式是把21的木板割成13,8,花费21,再把13割成5,8,花费13,共计34,当然也可以先割成16,5 ...

  7. Python 数据结构与算法 —— 哈弗曼树

    1. 从扩充二叉树到哈弗曼树 扩充二叉树:对二叉树 T,加入足够多的新叶节点(而不是任意),使 T 的原有结点都变成度数为 2 的分支节点,得到的二叉树称为 T 的扩充二叉树. 对于扩充二叉树而言, ...

  8. java实现哈弗曼树和哈夫曼树压缩

    本篇博文将介绍什么是哈夫曼树,并且如何在java语言中构建一棵哈夫曼树,怎么利用哈夫曼树实现对文件的压缩和解压.首先,先来了解下什么哈夫曼树. 一.哈夫曼树 哈夫曼树属于二叉树,即树的结点最多拥有2个 ...

  9. POJ 3253 Fence Repair【哈弗曼树/贪心/优先队列】

    Fence Repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 53645   Accepted: 17670 De ...

随机推荐

  1. Linux网络编程--wireshark分析TCP包头的格式

    摘要:     本文简介了TCP面向连接理论知识,具体讲述了TCP报文各个字段含义.并从Wireshark俘获分组中选取TCP连接建立相关报文段进行分析. 一.概述     TCP是面向连接的可靠传输 ...

  2. 五:Java之Vector类专题

    据说期末考试要考到Vector 这个类,出于复习须要在这里就要好好整理下这个类了. 一.基本概念 Vector 是可实现自己主动增长的对象数组. java.util.vector提供了向量类(vect ...

  3. android.app.Activity 的介绍

    发现当前Android的资料不是非常多,并且对于Activity的介绍也非常少.所以把官方文档的android.app.Activity的介绍翻译了一下,增加了一些自己的理解.各位假设认为我自己理解的 ...

  4. ABP入门系列(12)——如何升级Abp并调试源码

    ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 1. 升级Abp 本系列教程是基于Abp V1.0版本,现在Abp版本已经升级至V1.4.2(截至 ...

  5. 知名互联网公司校招 Java 开发岗面试知识点解析

    天之道,损有余而补不足,是故虚胜实,不足胜有余. 本文作者在一年之内参加过多场面试,应聘岗位均为 Java 开发方向.在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点. 主要包括以下几 ...

  6. jquery技巧小结

    由于主要还是负责后端,所以前端很多东西都不熟悉,jQuery作为web开发必备技能,有很多知识点,老是记不清楚,所以在这边整理一下. 1.加载页面后执行 $(function(){ //程序段 }) ...

  7. Maven版本号中隐藏的惊天大秘密

    一.背景 现在主流的Java系的互联网公司里,绝大多数公司都使用Maven作为依赖管理工具,一般我们对于依赖的版本号,常见两种类型:一种以“-RELEASE”结尾,另一种以“-SNAPSHOT”结尾. ...

  8. 理解Object.defineProperty()

    理解Object.defineProperty() Object.defineProperty() 方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象. 基本语法:Obj ...

  9. jmeter+ant+jenkins的自动化接口测试

    一.Jenkins安装配置 1.安装配置JDK1.7+环境变量: 2.下载jenkins.war,放入D:\jenkins目录下,目录位置随意: Jenkins启动方法: cmd进入Jenkins目录 ...

  10. 监听键盘弹起View上调

    可以用三方库IQKeyboardManager 用这个第三方 http://www.jianshu.com/p/f8157895 #pragma mark - keyboard events - // ...