哈弗曼,一个在几乎所有讲数据结构的书中都有出现过的人物,他的鼎鼎大名想必就不用我多说了。这一次来给大家讲解一下哈弗曼树的构建与哈弗曼编码的基本原理,有什么用呢?别急,还是先学会创建一棵哈弗曼树吧。
哈弗曼树又称最优二叉树,最优二叉树就是带权路径长度WPL最小的二叉树,那么我们就得搞清几个概念:
1. 路径长度:从树中的一个结点到另一个结点之间的分支构成这两个结点的路径,路径上的分支数目称为路径长度。
2. 树的路径长度:从树根到每一个结点的路径长度之和,我们所说的完全二叉树就是这种路径长度最短的二叉树。
3. 树的带权路径长度:如果在树的每一个叶子结点上赋上一个权值,那么树的带权路径长度就等于根结点到所有叶子结点的路径长度与叶子结点权值乘积的总和。
那么我们怎么判断一棵树是否为最优二叉树呢,先看看下面几棵树
他们的带权长度分别为:
WPL1:7*2+5*2+2*2+4*2=36
WPL2:7*3+5*3+2*1+4*2=46
WPL3:7*1+5*2+2*3+4*3=35
很明显,第三棵树的带权路径最短,这就是我们所说的最优二叉树(哈弗曼树),它的构建方法很简单,依次选取权值最小的结点放在树的底部,将最小的两个连接构成一个新结点,需要注意的是构成的新结点的权值应该等于这两个结点的权值之和,然后要把这个新结点放回我们需要构成树的结点中继续进行排序,这样构成的哈弗曼树,所有的存储有信息的结点都在叶子结点上。
下面一张图片就为大家演示了哈弗曼树的构建过程:
看了这么多,我们再来看看哈弗曼树的代码实现吧,假设我们要把一个数组中的元素封装到哈弗曼树中,那么我们需要做下面几件事:
1. 有一个容器来存放我们的哈弗曼树的结点
2. 有一个方法能够比较各个结点的权值大小进行排序
3.有一个打印二叉树结点的方法(先序,中序或者后序)
4.我们先要做一个测试用例,判断我们最后的结果是否正确
胡zong也总是教导我们,学会分析问题远远比代码本身更重要,分析问题的同时也体现了你的逻辑思维,最开始学习编程的时候,可能更多的时候是拿到一个问题先去写,再来发现问题,但是学习了一段时间之后,更加全面的考虑问题往往比解决当前问题更重要。
好的,不扯太远了,java的API中有一个优先队列(PriorityQueue<E>)的类,它的构造方法中有一个是可以放入一个比较器类比较队列中的元素,然后把最小的放到队列的头部,那么我们要进行一二步就变得简单了,如下:
//定义一个优先级队列来保存结点 PriorityQueue<TNode> queue=new PriorityQueue<TNode>(11,new MyComparator()); //创建一个比较器类 class MyComparator implements Comparator<TNode>{ public int compare(TNode n1,TNode n2){ return n1.data-n2.data; } }
打印树的结点的方法更简单:
/** * 先序遍历二叉树 */ public void PreOrderTraverse(TNode root){ if(root!=null){ System.out.print(root.data+" "); PreOrderTraverse(root.lchild); PreOrderTraverse(root.rchild); } }
最后就是我们的最重要的方法了:
/** * 将数组中的元素封装到哈弗曼树种 * @param arr 传入的数组元素 * @return 哈弗曼树的根结点 */ public TNode CreateHuffmanTree(int arr[]){ for(int i=0;i<arr.length;i++){ //将数组元素封装到队列当中 TNode node=new TNode(arr[i]); queue.add(node); } //如果队列的长度大于2则获取最小的两个结点 while(queue.size()>=2){ TNode lnode=queue.poll(); TNode rnode=queue.poll(); //将元素最小的两个结点连接起来产生一个新的结点 TNode node=new TNode(lnode.data+rnode.data); node.lchild=lnode; node.rchild=rnode; queue.add(node); } //如果只剩最后一个结点,那么这个结点就是根结点 TNode node=queue.poll(); return node; }
还有结点类:
class TNode{ int data;//数据域 TNode lchild,rchild;//左右孩子结点 public TNode(int data){ this.data=data; } }
讲完了这些,相信大家对于哈弗曼树也有了一定的认识,下面再简单讲解一下哈弗曼编码,至于编码的具体作用将在下次博客中提到:
构建好一颗二叉树后我们就可以对其进行编码了,编码的方式有两种:
1. 对所有的左子树路径都编码为1,右子树路径都编码为0。
2. 与第一条相反。
叶子结点的哈弗曼编码就是从根结点到该结点所经过的所有路径的编码的顺序组合。由于所经过的路径不可能重复,所以每一个叶子结点所对应的编码都是唯一的,而且,更重要的是,任意一个叶子结点的编码都不是其他叶子结点的前缀,这种编码叫做前缀编码。
如下就是一棵编码好的哈弗曼树:
如E结点的编码就是000,C的编码就是01。。。
好了,希望大家也能一起不断的汲取知识,软件行业,年轻的心需要更多的Energy。编程与就像体育锻炼一样,我们需要充满激情。
相关推荐
在实际应用中,哈弗曼编码常与其他压缩技术结合,如LZ77或LZ78,以提高压缩效率。此外,由于哈弗曼编码是无损的,解压缩后能完全恢复原始数据,因此它在文本、图像和音频压缩等领域都有广泛应用。 总结来说,哈弗曼...
在C语言下实现哈弗曼树的创建并进行哈弗曼编码,同时输出哈弗曼编码。
在C++实现哈弗曼编码与解码的过程中,通常包含以下几个关键步骤: 1. **计算字符频率**:首先,我们需要统计输入文本中各个字符的出现频率。这可以通过遍历文本并使用哈希表或数组记录每个字符出现的次数来完成。 ...
5. **编码与解码**:编码阶段将字符映射到对应的哈弗曼编码,形成编码表;解码阶段则根据编码表反向解析二进制流得到原始字符。 在"哈夫曼树的实现"这个文件中,很可能包含了具体的C++代码实现,包括以上提到的各个...
在这个课程设计中,我们将深入探讨哈弗曼编码的原理、构建过程以及如何实现编码与译码功能,同时支持文件的读写操作。 哈弗曼树,又称为最优二叉树或最小带权路径长度树,是根据字符出现频率构建的一种特殊的二叉树...
在本压缩包中的"Hamming Codes"可能是指汉明码,这是一种错误检测和纠正的编码方式,与哈弗曼编码不同,它不是用于数据压缩,而是通过添加冗余位来确保数据在传输或存储过程中的完整性。尽管两者在目的上有所差异,...
哈弗曼编码是一种高效的数据压缩方法,它利用了字符出现频率的不同来构建最优的二叉树,也称为哈弗曼树。在这个C++程序中,我们将会深入理解哈弗曼编码的原理及其在实际编码过程中的应用。 首先,我们要知道哈弗曼...
哈弗曼编码译码 哈弗曼树的建立,编码 对26个大写英文字母以及空格键的编码,译码
哈弗曼树,又称霍夫曼树,是一种特殊的二叉树,主要用于数据的高效编码,尤其是在数据压缩领域有着广泛的应用。...在实际应用中,如在文件压缩软件中,哈弗曼编码常常与其他压缩技术结合使用,以达到更好的压缩效果。
哈弗曼编码的生成是通过遍历哈弗曼树完成的,从根节点到每个叶子节点的路径代表该叶子节点字符的编码。左分支代表“0”,右分支代表“1”。 在实际应用中,哈弗曼树和编码解码常用于文本、图像等数据的压缩。例如,...
### 哈弗曼编码与解码 哈弗曼编码是一种广泛应用在计算机科学中的编码方式,主要用于数据压缩。它基于二叉树结构实现,并利用字符出现的频率来构造一棵特殊的二叉树——哈弗曼树(又称最优二叉树)。在本篇内容中,...
哈弗曼树编码是一种...程序首先处理输入数据,计算字符频率,然后构建哈弗曼树,最后输出每个字符对应的哈弗曼编码。通过对这个源文件的学习和理解,读者可以深入掌握哈弗曼编码原理以及C语言和数据结构的实际应用。
在压缩包文件"2019302130093许美琪"中,可能包含了C语言实现的哈弗曼编码算法源代码,包括创建哈弗曼树、编码和解码的函数。通过阅读和理解这段代码,可以深入学习哈弗曼编码的实现细节,如如何构造最小堆、如何进行...
哈弗曼树哈弗曼树哈弗曼树哈弗曼树哈弗曼树哈弗曼树哈弗曼树哈弗曼树哈弗曼树
哈弗曼编码是一种高效的数据压缩方法,源自于数据结构中的二叉树——哈弗曼树。在本数据结构实习中,我们将深入理解哈弗曼编码的原理、构建过程及其应用,包括字符编码及译文的生成,以及哈弗曼树的动态演示。 ...
利用哈弗曼树,我们可以生成哈弗曼编码,这是一种变长编码方法。每个字符对应一个唯一的二进制前缀码,短码用于频繁出现的字符,长码用于不常见的字符。这样可以减少编码后的平均位数,提高压缩效率。 哈弗曼编码的...
哈弗曼编码是一种高效的数据压缩方法,它基于一种特殊的二叉树——哈弗曼树(Huffman Tree),也称为最优二叉树。在MFC(Microsoft Foundation Classes)框架下,我们可以构建用户界面来实现哈弗曼编码和解码的过程...
- **编码生成**:哈弗曼编码的生成是构建哈弗曼树的重要后续步骤,但给定代码并未涉及。 - **性能优化**:使用优先队列(如C++ STL中的`priority_queue`)替换循环查找最小权重节点的过程,可以显著提高构建哈弗曼树...
构造一哈弗曼树并进行哈弗曼编码的源代码。
哈弗曼树的构造过程主要包括两个主要步骤:哈弗曼编码和构建哈弗曼树。 1. **哈弗曼编码**: - 首先,统计每个字符(或数据元素)的频率,频率表示该字符在文本中的出现次数。 - 将每个字符视为一个带权重的节点...