所谓哈夫曼树,又称为最优二叉树,要了解哈夫曼树,首先先来了解几个概念。树中一个结点到另一个结点之间的分支构成这两个结点之间的路径,路径上分支数目称为路径长度。树的长度是指从根结点到每一个叶子结点的路径长度之和。结点的带权路径长度为从从该结点到根结点之间的路径长度与结点上的权值的乘积。哈夫曼树就是带权路径长度最小的二叉树。现在我们可以根据给的任意一个整型数组构造一颗哈夫曼树,构造的思路是将数组中的每一个元素构造成结点对象,然后把每一个结点当成一棵树,将所有结点当成一片森林。然后每次从所有结点中取两个最小的结点,比较小的作为左子结点,比较大的作为右子结点,它们的和作为父结点构成一颗二叉树,然后把取出的这两个结点删除,将父结点放入剩下的结点中再重复以上过程直到最后只剩下一个结点,该结点即为哈夫曼树的根结点。从以上过程看,关键在于对数组的排序以及接收新的数组,这里用到java里面提供的优先队列PriorityQueue<E>,该队列的作用是将任意无序数组元素加入到该队列中,在该队列中这些元素会按某种顺序排好,只要按顺序取出就行了。查阅API文档可知,该队列定义了六个构造器,这里用到文档中的第四个构造器实例化一个该队列的对象,由该构造器的参数定义一个类来实现该参数接口类型,代码如下所示:
/**
* 实现比较对象类型接口类,该类作为优先队列的构造方法的参数传入
* @author lenovo
*
*/
class MyComparator implements Comparator<TreeNode>{
public int compare(TreeNode o1, TreeNode o2){
return (Integer)o1.getObj() - (Integer)o2.getObj();
}
public boolean equals(Object obj){
return false;
}
}
实现了该接口之后就可以实例化一个该队列的对象,然后将数组元素添加到该队列中,最后遍历队列,每次取出最小的两个元素,按上面思路就可以构造出哈夫曼树,具体代码如下所示:
/**
* 创建最优二叉树的方法
* @param arr:传入的数组
* @param TreeNode:返回根结点
*/
public TreeNode createHuffman(int[] arr){
//实例化一个优先队列对象
PriorityQueue<TreeNode> queue = new PriorityQueue<TreeNode>(11,new MyComparator());
TreeNode root=null;
//遍历数组,将数组元素构建成结点,并添加到队列中
for (int i=0;i<arr.length;i++){
//创建结点
TreeNode node = new TreeNode(arr[i]);
//将结点添加到队列中
queue.add(node);
}
//遍历队列,每次取出两个最小元素作为叶子结点,它们的和作为父结点建立二叉树,
//并从队列中删除这两个元素,同时把它们的父结点添加到队列中
while(queue.size()!=1){
//同时取两个最小元素
TreeNode node1 = queue.poll();
TreeNode node2 = queue.poll();
//根据取得的元素创建父结点
TreeNode fnode = new TreeNode((Integer)node1.getObj()+(Integer)node2.getObj());
//建立引用关系
if ((Integer)node1.getObj()<(Integer)node2.getObj()){//如果node1小于node2,则node1作为左子结点,node2作为右子结点
fnode.setLchild(node1);
fnode.setRchild(node2);
node1.setParent(fnode);
node2.setParent(node2);
}else {//如果node1大于于node2,则node1作为右子结点,node2作为左子结点
fnode.setLchild(node2);
fnode.setRchild(node1);
node1.setParent(fnode);
node2.setParent(node2);
}
//将父结点添加到队列中
queue.add(fnode);
root = fnode;
}
return root;
}
哈夫曼树生成之后,从根结点开始,对左子树分配代码“1”,右子树分配代码“0”,一直到达叶子结点为止,然后将从树根沿每条路径到达叶子结点的代码排列起来,就可以得到哈夫曼编码了,具体代码如下所示:
/**
* 根据根结点创建哈夫曼编码
* 规则:左子结点为:1,右子结点为:0
* @param root:根结点
*/
public void createCode(TreeNode root,String code){
//首先是确定各结点的路径
//得到子结点
TreeNode Lchild = root.getLchild();
TreeNode Rchild = root.getRchild();
//打印叶子节点
if (Lchild==null&&Rchild==null){
System.out.println(root.getObj()+"的编码为:"+code);
}
if (Lchild!=null){
//递归
createCode(Lchild,code+"1");
}
if (Rchild!=null){
//递归
createCode(Rchild,code+"0");
}
}
通过以下的主函数对上面的方法进行验证,主函数为:
/**
* 程序入口
* @param args
*/
public static void main(String args[]){
//实例化一个数组
int[] a = {8,6,3,4,9};
HuffmanTree ht = new HuffmanTree();
TreeNode root = ht.createHuffman(a);
ht.printTree(root);
System.out.println();
ht.createCode(root,"");
}
运行结果为:
30 13 6 7 3 4 17 8 9
6的编码为:11
3的编码为:101
4的编码为:100
8的编码为:01
9的编码为:00
通过检验可知结果正确,这就是自己对哈夫曼树的理解,如果有不正确的地方欢迎指正。
分享到:
相关推荐
#### 小结 通过上述代码,我们可以清晰地了解到哈夫曼树的创建过程及其带权路径长度的计算方法。哈夫曼树不仅在数据压缩中有重要作用,还在信息编码、网络通信等领域有着广泛的应用前景。通过理解这些基础算法,...
//m为结点数,一棵有n个叶子结点的哈夫曼树共有2n-1个结点,可以存储在一个大小为2n-1的一维数组中 HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号单元未用 //--------初始化哈弗曼树------- for(p=HT+1,i=...
在哈夫曼树中,权值较小的节点通常位于较浅的层次,权重较大的节点则在较深的层次。这个特性使得频繁出现的字符编码更短,从而降低数据的存储和传输成本。 2. **哈夫曼编码** 哈夫曼编码是为每个字符分配一个唯一...
将已在内存中的哈夫曼树以直观的方式(树或凹凸表形式)显示在屏幕上,同时将此字符形式的哈夫曼树写入文件treeprint中。 实现提示: 1、用户界面可以设计为“菜单”方式:显示上述功能号,再加上“E”表示结束运...
在哈夫曼树中,没有度为1的结点,结点总数是n0+n2(其中n0表示二叉树中度为0的结点数,n2表示度为2的结点数),而由二叉树的性质知道n0=n2+1,所以一棵哈夫曼树中结点总数是2n0-1。 由此可以得出:任何n个字符的...
哈夫曼树(Huffman Tree)是一种特殊的二叉树,用于数据压缩,通过构建具有最小带权路径长度的二叉树来实现。哈夫曼编码是基于哈夫曼树生成的,频率高的字符编码较短,频率低的字符编码较长,从而实现高效的数据压缩...
哈夫曼树是根据给定的权值集合构造的,它的特点是:有n个叶子结点,没有度为1的结点,总的结点数为2n-1,深度≤n-1,形态不唯一。 哈夫曼树的构造可以使用哈夫曼算法,哈夫曼算法的步骤是: 1. 根据给定的n个权值{...
哈夫曼树和哈夫曼编码是数据结构中的一种重要概念,哈夫曼树是一种特殊的二叉树,它可以用来构造最优的前缀编码。哈夫曼编码是一种变长编码方法,它可以使得总的编码长度最短。 哈夫曼树的定义是指带权路径长度最小...
哈夫曼树(Huffman Tree)是一种特殊的二叉树,它的特点是:有 n 个叶子结点,不存在度为 1 的结点,总的结点数为 2n-1,深度≤ n-1,形态不唯一。哈夫曼树的定义是:带权路径长度 WPL 最小的二叉树。哈夫曼树的构建...
利用哈夫曼编码进行信息通讯可以大大提高信道利用率,缩短信息传输时间,降低传输成本。...将已在内存中的哈夫曼树以直观的方式 (树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件treeprint中。
#### 小结 通过本次实验,不仅能够深入了解哈夫曼编码的工作原理,还能掌握其实现方法。这对于数据压缩领域以及更广泛的计算机科学领域都有着重要的意义。此外,该实验还能够培养编程技能和解决问题的能力,有助于...
3. 完成课程设计报告,包括问题分析、总体设计、详细设计、测试报告、小结和软件使用说明。 课程设计报告中,需要特别注意的是,哈夫曼树的构建和编码过程,以及如何处理码文件最后一字节的多余位信息。在处理位串...
具体需求包括:\n\n- 初始化:读取DataFile.data中的字符及其权值,构建哈夫曼树(HuffTree)。\n- 编码:利用哈夫曼树对ToBeTran.data中的文本进行编码,生成的编码保存在Code.txt中。\n- 译码:根据CodeFile.data...
六、小结 通过哈夫曼编码/译码器的设计,学生不仅掌握了哈夫曼编码的原理,还锻炼了程序设计、数据结构应用和问题解决的能力。这个过程有助于提升对数据结构的理解,为今后的计算机科学学习和实践打下坚实基础。
- 通过个人设计小结,每个成员反思自己的工作,并提出下一步改进方向。 8. **相关技术**: - 熟悉C/C++编程语言,可能还涉及到MFC库,用于构建图形用户界面。 - 二进制文件的读写操作,以及统计分析,对于构建...
本项目旨在实现一个基于哈夫曼编码原理的编译码器,该编译码器能够统计文本文件中字符的出现频率,并以此为基础构建哈夫曼树,进而对文件进行编码压缩和解码还原。 #### 概要设计 本系统主要分为三个阶段:初始化...
哈夫曼树是哈夫曼编码的核心结构,指所有叶子结点的二叉树中带权路径长度最小的二叉树。也称最优二叉树树的带权路径长度:从树的根节点到该节点的路径长度与该节点权的乘积之和。 哈夫曼编码实现图像压缩的基本原理...