主要内容完全二叉树Huffman算法
最优二叉树(哈夫曼树)的构建及编码
最优⼆叉树(哈夫曼树)的构建及编码参考:数据结构教程(第五版)李春葆主编⼀,概述1,概念 结点的带权路径长度: 从根节点到该结点之间的路径长度与该结点上权的乘积。
树的带权路径长度: 树中所有叶结点的带权路径长度之和。
2,哈夫曼树(Huffman Tree) 给定 n 个权值作为 n 个叶⼦结点,构造⼀棵⼆叉树,若该树的带权路径长度达到最⼩,则称这样的⼆叉树为最优⼆叉树,也称为哈夫曼树。
哈夫曼树是带权路径长度最短的树,权值较⼤的结点离根较近。
⼆,哈夫曼树的构建1,思考 要实现哈夫曼树⾸先有个问题摆在眼前,那就是哈夫曼树⽤什么数据结构表⽰? ⾸先,我们想到的肯定数组了,因为数组是最简单和⽅便的。
⽤数组表⽰⼆叉树有两种⽅法: 第⼀种适⽤于所有的树。
即利⽤树的每个结点最多只有⼀个⽗节点这种特性,⽤ p[ i ] 表⽰ i 结点的根节点,进⽽表⽰树的⽅法。
但这种⽅法是有缺陷的,权重的值需要另设⼀个数组表⽰;每次找⼦节点都要遍历⼀遍数组,⼗分浪费时间。
第⼆种只适⽤于⼆叉树。
即利⽤⼆叉树每个结点最多只有两个⼦节点的特点。
从下标 0 开始表⽰根节点,编号为 i 结点即为 2 * i + 1 和 2 * i + 2,⽗节点为 ( i - 1) / 2,没有⽤到的空间⽤ -1 表⽰。
但这种⽅法也有问题,即哈夫曼树是从叶结点⾃下往上构建的,⼀开始树叶的位置会因为⽆法确定⾃⾝的深度⽽⽆法确定,从⽽⽆法构造。
既然如此,只能⽤⽐较⿇烦的结构体数组表⽰⼆叉树了。
typedef struct HTNode // 哈夫曼树结点{double w; // 权重int p, lc, rc;}htn;2,算法思想 感觉⽐较偏向于贪⼼,权重最⼩的叶⼦节点要离根节点越远,⼜因为我们是从叶⼦结点开始构造最优树的,所以肯定是从最远的结点开始构造,即权重最⼩的结点开始构造。
所以先选择权重最⼩的两个结点,构造⼀棵⼩⼆叉树。
然后那两个最⼩权值的结点因为已经构造完了,不会在⽤了,就不去考虑它了,将新⽣成的根节点作为新的叶⼦节加⼊剩下的叶⼦节点,⼜因为该根节点要能代表整个以它为根节点的⼆叉树的权重,所以其权值要为其所有⼦节点的权重之和。
二叉树霍夫曼编码
霍夫曼编码(Huffman Coding)是一种可变字长编码(VLC)方法,它完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码。
为了实现这种更高效的编码方式,就需要利用一个二叉树的结构来进行辅助编码,这种二叉树即为霍夫曼树,也称作最优二叉树。
具体来说,霍夫曼编码的构建过程如下:
将N个权值作为N个叶子节点,构造一棵二叉树。
通过将权值最小的两个节点构建成一个小二叉树,然后将这个小二叉树链接到另一棵只含一个根节点的小二叉树上,以此构造一棵霍夫曼树。
重复以上步骤,直到所有的节点都被包含在霍夫曼树内。
在构建霍夫曼树的过程中,为了使编码的平均长度最小,权值大的节点使用较短的路径,而权值小的节点使用较长的路径。
霍夫曼编码是通过对霍夫曼树的叶子节点进行遍历来获得的,从根节点到每个叶子节点的路径可以看作一种编码,具有最小权值的叶子节点的路径将被赋予0,而其他路径则被赋予1。
总的来说,霍夫曼编码是基于霍夫曼树的一种非常有效的编码方法,它能够实现对字符的平均长度最短的编码,广泛应用于数据压缩等领域。
Huffman树
数据结构 赵帅锋 zsf@
Huffman编码
/* 在HT[1,…,i-1]中选择parent为0,且weight最小的两个 结点,序号为s1和s2*/ Select( HT, i – 1, s1, s2 ); HT[s1].parent = i; HT[s2].parent = i; HT[i].lChild = s1; HT[i].rChild = s2; HT[i].weight = HT[s1].weight + HT[s2].weight;
数据结构 赵帅锋 zsf@
Huffman树
不及格 及格 中等 良好 优秀 0-59 60-69 70-79 80-89 90-100 0.05 0.15 0.40 0.30 0.10 WPL = 0.05 * 4 中等 及格 及格 不及格 优秀 + 0.1 * 4
数据结构 赵帅锋 zsf@
Huffman编码
前缀编码方法:
设有n种字符,在一个电文中,第i种字符出 现的次数为Wi,编码长度为li,则一段电文的 总长度为: L = w1l1 + w2l2 + … + wnln = ∑ wili 使L最小,可以看作是已知n个结点的权wi, 求一棵Huffman树的问题。由此得到的二进 制编码,称为Huffman编码。
2.
编码:对于每一个叶子结点,其Huffman编 码就是该结点到根结点的路径编码(01…) 的逆序。
1. 2.
从该结点开始,按层次搜索。 若该结点是左孩子,则编码为0,否则编码为1
数据结构 赵帅锋 zsf@
Huffman编码
void HuffmanCoding( HuffmanTree &HT, HuffmanCode &HC, int *w, int n) { if( n<=1 ) { return ERROR; } m = 2 * n – 1; // 初始化Huffman树 HT = (HuffmanTree )malloc( (m+1) * sizeof( HTNode )); if( !HT ) { return OVERFLOW; }
哈夫曼树及哈夫曼编码的算法实现c语言
哈夫曼树及哈夫曼编码的算法实现c语言1.引言1.1 概述哈夫曼树及哈夫曼编码是数据压缩和编码中常用的重要算法。
哈夫曼树由大卫·哈夫曼于1952年提出,用于根据字符出现的频率构建一种最优的前缀编码方式。
而哈夫曼编码则是根据哈夫曼树构建的编码表将字符进行编码的过程。
在现代通信和计算机领域,数据传输和存储中往往需要大量的空间。
为了有效利用有限的资源,减少数据的存储和传输成本,数据压缩成为一个重要的技术。
而哈夫曼树及哈夫曼编码正是数据压缩中常用的技术之一。
哈夫曼树的概念及原理是基于字符的频率和概率进行构建的。
在哈夫曼树中,字符出现频率越高的节点越接近根节点,出现频率越低的节点离根节点越远。
这种构建方式保证了哈夫曼树的最优性,即最小化编码的总长度。
哈夫曼编码的算法实现是根据哈夫曼树构建的编码表进行的。
编码表中,每个字符都与一段二进制编码相对应。
在进行数据压缩和解压缩时,通过查表的方式将字符转化为相应的二进制编码,或将二进制编码解析为原始字符。
本文旨在介绍哈夫曼树及哈夫曼编码的概念和原理,并通过C语言实现算法。
通过深入理解哈夫曼树及哈夫曼编码的实现过程,可以更好地理解数据压缩和编码的原理,为后续的研究和应用提供基础。
接下来,我们将首先介绍哈夫曼树的概念和原理,然后详细讲解哈夫曼编码的算法实现。
最后,我们将总结哈夫曼树及哈夫曼编码的重要性,并提出对哈夫曼树和哈夫曼编码进一步研究的方向。
让我们一起深入探索哈夫曼树及哈夫曼编码的奥秘吧!1.2 文章结构文章结构部分的内容可以包括以下内容:文章结构部分主要介绍了本文的组织结构和各个章节的内容概述,以帮助读者更好地理解全文的逻辑结构和内容安排。
首先,本文包括引言、正文和结论三个部分。
引言部分主要对哈夫曼树及哈夫曼编码的算法实现进行了概述,包括相关的概念、原理和目的。
正文部分则深入介绍了哈夫曼树的概念和原理,以及哈夫曼编码的算法实现。
最后,结论部分对本文的主要内容进行了总结,并提出了对哈夫曼树和哈夫曼编码的进一步研究方向。
哈夫曼算法的理解及原理分析算法实现构造哈夫曼树的算法
哈夫曼算法的理解及原理分析算法实现构造哈夫曼树的算法哈夫曼算法(Huffman Algorithm)是一种贪心算法,用于构建最优二叉树(也称为哈夫曼树或者最优前缀编码树),主要用于数据压缩和编码。
它通过统计字符出现的频率来构建一个编码表,将较频繁出现的字符用较短的编码表示,从而减少存储空间和传输带宽。
原理分析:1.统计字符出现的频率:遍历待编码的字符串,统计每个字符出现的次数。
2.构建哈夫曼树:根据字符频率构建二叉树,频率越高的字符位置越靠近根节点,频率越低的字符位置越远离根节点。
构建哈夫曼树的通常做法是使用最小堆来存储频率,并反复合并堆中最小的两个节点,直到堆中只剩一个节点,即根节点。
3.生成编码表:从根节点开始,沿着左子树为0,右子树为1的路径将所有叶子节点的编码存储在一个编码表中。
算法实现:下面是一个简单的Python实现示例:```pythonclass Node:def __init__(self, char, freq):self.char = charself.freq = freqself.left = Noneself.right = Nonedef build_huffman_tree(text):#统计字符频率freq_dict = {}for char in text:if char in freq_dict:freq_dict[char] += 1else:freq_dict[char] = 1#构建最小堆heap = []for char, freq in freq_dict.items(: node = Node(char, freq)heap.append(node)heap.sort(key=lambda x: x.freq)#构建哈夫曼树while len(heap) > 1:left = heap.pop(0)right = heap.pop(0)parent = Node(None, left.freq + right.freq) parent.left = leftparent.right = rightheap.append(parent)heap.sort(key=lambda x: x.freq)root = heap[0]#生成编码表code_table = {}generate_code(root, "", code_table)return code_tabledef generate_code(node, code, code_table):if node.char:code_table[node.char] = codereturngenerate_code(node.left, code + "0", code_table) generate_code(node.right, code + "1", code_table) ```构造哈夫曼树的算法:上述的 `build_huffman_tree` 函数通过统计频率构建了最小堆`heap`,然后不断地合并最小的两个节点,直到堆中只剩下一个节点,即哈夫曼树的根节点。
自适应霍夫曼编码
哈尔滨工业大学(威海)自适应霍夫曼编码信息论论文隋沛君10S030092一、霍夫曼编码概述:Huffman 算法是一种用于数据压缩的算法,由D.A. Huffman 最先提出。
它完全依据字符出现概率来构造平均长度最短的编码,有时称之为最佳编码,一般叫做Huffman编码。
频繁使用的数据用较短的代码代替,较少使用的数据用较长的代码代替,每个数据的代码各不相同。
这些代码都是二进制码,且码的长度是可变的。
该编码的核心部分为Huffman编码树,一棵满二叉树。
所有可能的输入符(通常对应为字节)在Huffman编码树上对应为一个叶节点,叶节点的位置就是该符号的Huffman编码。
具体来说,一个符号对应的Huffman 编码就是从根节点开始,沿左字节点0或右子节点1前进,一直找到该符号叶节点为止的路径对应的二进制编码。
在Huffman编码树的基础上,该算法的编码部分输入一系列的符号,根据Huffman树对符号进行翻译,以符号在Huffman树上的位置作为编码结果。
解码部分反之,根据输入的Huffman编码,通过查询Huffman树翻译回原始符号。
现在使用中的霍夫曼编码大致分为两种:静态霍夫曼编码和自适应霍夫曼编码。
二、静态霍夫曼编码简介:编码步骤:第一,将信源符号按照权重(即该符号出现的概率)递减顺序排序。
第二,取出权重最小的两个集合元素作为叶节点组成一棵子树,子树的根节点权重值为两个叶节点的权重值之和。
然后将新产生的子树的根节点元素替代原两个叶子节点元素放回原来的集合,并保持集合有序。
每次形成子树时,将两个叶子节点分别赋予1和0或0和1。
第三,重复上述步骤,直至集合中只剩下一个元素,则Huffman 编码树构造完成。
第四,对每一个信源符号写出从编码树的根节点到叶子节点的1,0序列。
编码实例:abcddbb最终编码结果:1000101111100三、自适应霍夫曼编码提出的目的和意义:在静态霍夫曼编码中,要构造编码树必须提前统计被编码对象中的符号出现概率,因此必须对输入符号流进行两遍扫描,第一遍统计符号出现概率并构造编码树,第二遍进行编码,这在很多实际应用的场合中之不能接受的。
32.二叉树与最优二叉树
0 1 2 3 4 5 30% 20% 15% 10% 10% 5% 6 5% 7 5%
求传输它们的最佳前缀 码。
参考答案: 0 01 1 11 2 3 4 5 6 7 1001
001 101 0000 0001 1000
教师:田检
30
教师:田检
60 20 10 15 10 15 0 01 10 5 0 00 1 5 0 00 00 5 0 00 01 0 10 10 0 11 0 10 0 11 1 20 10
40 20
25
35
10 1 11
1 10
图 9.2.11
w0=20; w1=15;w2=10;w3=10; w4=10; w5=5; w6=10; w7=5; w8=10;w9=5。
教师:田检
26
解 (1)令i对应树叶权为wi,wi=100i,则 w0=20;w1=15;
w2=10;w3=10; w4=10;w5=5; w6=10;w7=5; w8=10;w9=5。 构造一棵带权5,5,5,10,10,10,10,10,15, 20的最优二叉树。
教师:田检
27
1 00 0 —10 1 —01 0 2 —11 1 3 —11 0 4 —01 11 5 —00 01 6 —01 10 7 —00 00 1 8 —00 1 9 —00 00 0
31
16 16
10 10
最优二叉树不唯一!
6
6
4
6 3
1
3
2
4
6
3
1 2
3
教师:田检
18
练习 1:求带权为 2,4,7,8,10,12的最优二叉树 43
计算机数据结构知识点梳理 哈夫曼(Huffman)树和哈夫曼编码
(3)在集合F中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入 到集合F中;
(4)重复(2)(3)两步,当F中只剩下一棵二叉树时,这棵二叉树便是所要 建立的哈夫曼树。
(3)深度为h的哈夫曼树,其叶子结点的最大编码长度为h-1。
[题1]若度为m的哈夫曼树,其叶子结点个数为n,则非叶子结点 的个数为( )。
A.n-1 B.[n/m]-1 C.[(n-1)/(m-1)] D.[n/(m-1)]-1
分析:在构造度为m的哈夫曼树过程中,每次把m个子结点合并 为一个父结点(第一次合并可能少于m个子结点),每次合并 减少m-1个结点,从n个叶子结点减少到最后只剩一个父结点共 需[(n-1)/(m-1)]次合并,每次合并增加一个非叶子结点。
5、对哈夫曼树编码的总结
(1)哈夫曼编码是能使电文代码总长最短的编码方式。此结论由哈夫曼树是带 权路径长度最小的树的特征可得。
(2)哈夫曼编码是一种前缀编码,保证其在译码时不会产生歧义。因为,在哈 夫曼编码中,每个字符都是叶子结点,而叶子结点不可能从根结点到其他叶 子结点的路径上,所以一个字符的哈夫曼编码不可能是另一个字符的哈夫曼 编码的前缀。
知识点10:哈夫曼(HUFFMAN)树和哈夫曼编码
1、哈夫曼树(又称最优二叉树),是指对于一 组带有确定权值的叶结点,构造的具有最小带
权路径长度的二叉树。
2、哈夫曼树的构造方法的基本思想
(1)由给定的n个权值{W1,W2,…,Wn}构造n棵只有一个叶结点的二叉树, 从而得到一个二叉树的集合F={T1,T2,…,Tn};
哈夫曼编码算法与分析
算法与分析1.哈夫曼编码是广泛地用于数据文件压缩的十分有效的编码方法。
给出文件中各个字符出现的频率,求各个字符的哈夫曼编码方案。
2.给定带权有向图G =(V,E),其中每条边的权是非负实数。
另外,还给定V中的一个顶点,称为源。
现在要计算从源到所有其他各顶点的最短路长度。
这里路的长度是指路上各边权之和。
3.设G =(V,E)是无向连通带权图,即一个网络。
E中每条边(v,w)的权为c[v][w]。
如果G的子图G’是一棵包含G的所有顶点的树,则称G’为G的生成树。
生成树上各边权的总和称为该生成树的耗费。
在G的所有生成树中,耗费最小的生成树称为G的最小生成树。
求G的最小生成树。
求解问题的算法原理:1.最优装载哈夫曼编码1.1前缀码对每一个字符规定一个0,1串作为其代码,并要求任一字符的代码都不是其它字符代码的前缀,这种编码称为前缀码。
编码的前缀性质可以使译码方法非常简单。
表示最优前缀码的二叉树总是一棵完全二叉树,即树中任一结点都有2个儿子结点。
平均码长定义为:B(T)=∑∈CcTcdcf)()(f(c):c的码长,dt(c):c的深度使平均码长达到最小的前缀码编码方案称为给定编码字符集C的最优前缀码。
1.2构造哈夫曼编码哈夫曼提出构造最优前缀码的贪心算法,由此产生的编码方案称为哈夫曼编码。
哈夫曼算法以自底向上的方式构造表示最优前缀码的二叉树T。
算法以|C|个叶结点开始,执行|C|-1次的“合并”运算后产生最终所要求的树T。
编码字符集中每一字符c的频率是f(c)。
以f为键值的优先队列Q用在贪心选择时有效地确定算法当前要合并的2棵具有最小频率的树。
一旦2棵具有最小频率的树合并后,产生一棵新的树,其频率为合并的2棵树的频率之和,并将新树插入优先队列Q。
经过n-1次的合并后,优先队列中只剩下一棵树,即所要求的树T。
可用最小堆实现优先队列Q。
2.单源最短路径Dijkstra算法是解单源最短路径问题的贪心算法。
其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合。
数据结构——哈夫曼(Huffman)树+哈夫曼编码
数据结构——哈夫曼(Huffman)树+哈夫曼编码前天acm实验课,⽼师教了⼏种排序,抓的⼀套题上有⼀个哈夫曼树的题,正好之前离散数学也讲过哈夫曼树,这⾥我就结合课本,整理⼀篇关于哈夫曼树的博客。
哈夫曼树的介绍Huffman Tree,中⽂名是哈夫曼树或霍夫曼树,它是最优⼆叉树。
定义:给定n个权值作为n个叶⼦结点,构造⼀棵⼆叉树,若树的带权路径长度达到最⼩,则这棵树被称为哈夫曼树。
这个定义⾥⾯涉及到了⼏个陌⽣的概念,下⾯就是⼀颗哈夫曼树,我们来看图解答。
(01) 路径和路径长度定义:在⼀棵树中,从⼀个结点往下可以达到的孩⼦或孙⼦结点之间的通路,称为路径。
通路中分⽀的数⽬称为路径长度。
若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
例⼦:100和80的路径长度是1,50和30的路径长度是2,20和10的路径长度是3。
(02) 结点的权及带权路径长度定义:若将树中结点赋给⼀个有着某种含义的数值,则这个数值称为该结点的权。
结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
例⼦:节点20的路径长度是3,它的带权路径长度= 路径长度 * 权 = 3 * 20 = 60。
(03) 树的带权路径长度定义:树的带权路径长度规定为所有叶⼦结点的带权路径长度之和,记为WPL。
例⼦:⽰例中,树的WPL= 1*100 + 2*50 +3*20 + 3*10 = 100 + 100 + 60 + 30 = 290。
⽐较下⾯两棵树上⾯的两棵树都是以{10, 20, 50, 100}为叶⼦节点的树。
左边的树WPL=2*10 + 2*20 + 2*50 + 2*100 = 360 右边的树WPL=350左边的树WPL > 右边的树的WPL。
你也可以计算除上⾯两种⽰例之外的情况,但实际上右边的树就是{10,20,50,100}对应的哈夫曼树。
⾄此,应该堆哈夫曼树的概念有了⼀定的了解了,下⾯看看如何去构造⼀棵哈夫曼树。
哈夫曼树算法
哈夫曼树算法
哈夫曼树算法是一种常用的树形数据结构,也被称为最优二叉树算法。
它是由美国计算机科学家David A. Huffman于1952年发明的,用于数据压缩和编码的问题中。
哈夫曼树算法的基本思想是,将出现频率较高的字符编码为较短的二进制序列,而将出现频率较低的字符编码为较长的二进制序列,以达到压缩数据的目的。
这种编码方式被称为哈夫曼编码。
哈夫曼树算法的构建过程是从数据源中选出频率最小的两个数据,将它们合并成一个新的节点,其权重为这两个数据的权重之和。
然后再将这个新节点加入到数据源中,重复这个过程,直到数据源中只剩下一个节点,这个节点就是哈夫曼树的根节点。
哈夫曼树的权重值是所有叶子节点的权重乘以它们的深度之和,也是数据压缩的效率指标。
哈夫曼树算法可以用来解决许多经典的问题,如最优合并策略、最优缩短编码长度等。
总之,哈夫曼树算法是一种非常重要的算法,对于数据压缩和编码问题有着广泛的应用。
它的实现方法也比较简单,但是需要对数据源进行一定的分析和预处理,以得到最优的数据压缩效果。
- 1 -。
哈夫曼Huffman树及应用
8 11 11 0 0
9 8 11 1 7
10 15 12 3 4
哈夫曼树
11 19 13 8 9 12 29 14 5 10
哈夫曼树对应的静态三叉链表13 58 15 6 11
14 100 0 13 14
w,p,lch,rch 是 weight,parent, lchild,rchild
的缩写
哈夫曼算法
如何得到使二进制 串总长最短编码
应用中每个字符的使用频率是不一样的。显然,为使传输 的二进制串尽可能的短,使用频率高的字符用较短编码,使用 频率低的字符用较长编码,电文总长= 原文中字符总数(字符x 使用频率 字符x编码长度)
为设计电文总长最短编码,可通过构造以字符使用频率作 为权值的哈夫曼树实现。
例 某通讯系统只使用8种字符a、b、c、d、e、f、g、h,其使用频率分别为 0.05,0.29,0.07,0.08, 0.14,0.23, 0.03,0.11。构造以字符使用频率作为权值的哈夫曼 树。,将权值取为整数w=(5,29,7,8,14,23,3,11),按哈夫曼算法构造的一棵哈夫曼 树如下:
Y
a<70 N C
a<80
N a<90 Y
N
B
A
4 哈夫曼编码
哈夫曼树除了能求解最优判定问题解,还用于其他一些最优问题的
求解。这里介绍用哈夫曼树求解数据的二进制编码。
在进行数据通讯时,涉及数据编码问题。所谓数据编码就是数据与
二进制字符串的转换。例如:邮局发电报,发送方将原文转换成二进制
字符串,接收方将二进制字符串还原成原文。
1)构造以 a、b、c、d、e、f、g、h为叶子结点的二叉树; 2)将该二叉树所有左分枝标记 0,所有右分枝标记1;
数据结构与算法:哈夫曼树
数据结构与算法:哈夫曼树哈夫曼树给定N个权值作为N个叶⼦结点,构造⼀棵⼆叉树,若该树的带权路径长度达到最⼩,称这样的⼆叉树为最优⼆叉树,也称为哈夫曼树(Huffman Tree)。
哈夫曼树是带权路径长度最短的树,权值较⼤的结点离根较近。
重要概念路径:从⼀个节点到它往下可以达到的节点所经shu过的所有节点,称为两个节点之间的路径路径长度:即两个节点的层级差,如A节点在第⼀层,B节点在第四层,那它们之间的路径长度为4-1=3权重值:为树中的每个节点设置⼀个有某种含义的数值,称为权重值(Weight),权重值在不同算法中可以起到不同的作⽤节点的带权路径长度:从根节点到该节点的路径长度与该节点权重值的乘积树的带权路径长度:所有叶⼦节点的带权路径长度之和,也简称为WPL哈夫曼树判断判断⼀棵树是不是哈夫曼树只要判断该树的结构是否构成最短带权路径。
在下图中3棵同样叶⼦节点的树中带权路径最短的是右侧的树,所以右侧的树就是哈夫曼树。
代码实现案例:将数组{13,7,8,3,29,6,1}转换成⼀棵哈夫曼树思路分析:从哈夫曼树的概念中可以看出,要组成哈夫曼树,权值越⼤的节点必须越靠近根节点,所以在组成哈夫曼树时,应该由最⼩权值的节点开始。
步骤:(1) 将数组转换成节点,并将这些节点由⼩到⼤进⾏排序存放在集合中(2) 从节点集合中取出权值最⼩的两个节点,以这两个节点为⼦节点创建⼀棵⼆叉树,它们的⽗节点权值就是它们的权值之和(3) 从节点集合中删除取出的两个节点,并将它们组成的⽗节点添加进节点集合中,跳到步骤(2)直到节点集合中只剩⼀个节点public class HuffmanTreeDemo {public static void main(String[] args) {int array[] = {13,7,8,3,29,6,1};HuffmanTree huffmanTree = new HuffmanTree();Node root = huffmanTree.create(array);huffmanTree.preOrder(root);}}//哈夫曼树class HuffmanTree{public void preOrder(Node root){if (root == null){System.out.println("哈夫曼树为空,⽆法遍历");return;}root.preOrder();}/*** 创建哈夫曼树* @param array 各节点的权值⼤⼩* @return*/public Node create(int array[]){//先将传⼊的各权值转成节点并添加到集合中List<Node> nodes = new ArrayList<>();for (int value : array){nodes.add(new Node(value));}/*当集合中的数组只有⼀个节点时,即集合内所有节点已经组合完成,剩下的唯⼀⼀个节点即是哈夫曼树的根节点*/while (nodes.size() > 1){//将节点集合从⼩到⼤进⾏排序//注意:如果在节点类没有实现Comparable接⼝,则⽆法使⽤Collections.sort(nodes);//在集合内取出权值最⼩的两个节点Node leftNode = nodes.get(0);Node rightNode = nodes.get(1);//以这两个节点创建⼀个新的⼆叉树,它们的⽗节点的权值即是它们的权值之和Node parent = new Node(leftNode.weight + rightNode.weight);parent.left = leftNode;parent.right = rightNode;//再从集合中删除已经组合成⼆叉树的俩个节点,并把它们俩个的⽗节点加⼊到集合中nodes.remove(leftNode);nodes.remove(rightNode);nodes.add(parent);}//返回哈夫曼树的根节点return nodes.get(0);}}//因为要在节点的集合内,以节点的权值value,从⼩到⼤进⾏排序,所以要实现Comparable<>接⼝class Node implements Comparable<Node>{int weight;//节点的权值Node left;Node right;public Node(int weight) {this.weight = weight;}public void preOrder(){System.out.println(this);if (this.left != null){this.left.preOrder();}if (this.right != null){this.right.preOrder();}}@Overridepublic String toString() {return "Node{" +"weight=" + weight +'}';}@Overridepublic int compareTo(Node o) {return this.weight - o.weight;}}哈夫曼编码定长编码固定长度编码⼀种⼆进制信息的信道编码。
哈夫曼编码
例2:假设用于通信的电文仅由8个字母
{a, b, c, d, e, f, g, h} 构成,它们在电文中出现的概率分别为{ 0.07, 0.19, 0.02, 0.06, 0.32, 0.03, 0.21, 0.10} ,试为这8个字母设计 哈夫曼编码。如果用0~7的二进制编码方案又如何?
解:先将概率放大100倍,以方便构造哈夫曼树。 权值集合 w={7, 19, 2, 6, 32, 3, 21, 10}, 按哈夫曼树构造规则(合并、删除、替换),可得到哈夫曼树。
14
采用顺序表实现对Huffman编码的存储 //---------------Huffman编码存储结构-----------------typedef struct { char ch; int start; char bits[n+1]; }HuffmanCode; typedef HuffmanCode HCode[n]; ch存放对应的字符,start存放Huffman编码在字符 数组bits[]中开始的位置。
17
FileExtract(void) 初始条件:压缩结果文件Code.txt和tail.txt存在。 操作结果: 将code.txt和tail.txt中的字符写成编码的二进制字符形式, 写进file00.txt。 FileTrans(HTree T,HCode H,int N) 初始条件: 已生成File00,txt并已求得各个字符的Huffman编码, Huffman树已建立。 操作结果:将Huffman编码翻译成原文件,写入translated.txt。 }ADT 还需要包含调用若干库文件:stdio.h, malloc.h, string.h。
13
概要分析
采用顺序表实现对Huffman树的存储 //---------------Huffman树存储结 构-----------------typedef struct { int weight; int lchild, rchild, parent; }HuffmanTree; typedef HuffmanTree HTree[m]; weight域存有该节点字符的权值,lchild、 rchild、parent分别存放该节点的左孩子、 右孩子和双亲节点在顺序表中的位置。
哈夫曼树构造方法
哈夫曼树构造方法哈夫曼树(Huffman Tree)是一种广泛应用于数据压缩和编码的二叉树结构。
它是一种最优二叉树,即带权路径长度最短的二叉树。
哈夫曼树的构造方法主要有两种:贪心算法和分治算法。
1. 贪心算法:哈夫曼树的贪心算法是一种自底向上(从叶子节点到根节点)的构造方法。
首先,根据给定的权值列表,将每个权值看作一个独立的节点,并按照权值从小到大的顺序构建一个森林。
然后,从森林中选择权值最小的两个节点(可以使用最小堆来实现),将它们合并为一个新的节点,并将新节点的权值设为两个被合并节点的权值之和。
将新节点插入到森林中,并移除原来的两个节点。
重复上述步骤,直到森林中只有一个节点为止,该节点就是哈夫曼树的根节点。
贪心算法构造哈夫曼树的时间复杂度为O(nlogn),n为节点数量。
2. 分治算法:哈夫曼树的分治算法是一种自顶向下(从根节点到叶子节点)的构造方法。
首先,将给定的权值列表按照权值从小到大的顺序排序。
然后,将权值最小的两个节点合并为一个新的节点,并将新节点的权值设为两个被合并节点的权值之和。
将新节点插入到排序后的列表中,并移除原来的两个节点。
重复上述步骤,直到列表中只有一个节点为止,该节点就是哈夫曼树的根节点。
分治算法构造哈夫曼树的时间复杂度为O(n^2),n为节点数量。
无论是贪心算法还是分治算法,构造出的哈夫曼树都具有最优性质,即带权路径长度最短。
由于贪心算法的时间复杂度较低,因此在实际应用中更为常用。
另外,构造哈夫曼树的方法除了贪心算法和分治算法外,还可以使用动态规划等其他方法。
对于哈夫曼树的应用,最常见的是数据压缩和编码。
哈夫曼树可以根据字符出现的频率构建对应的编码表,将频率高的字符用较短的编码表示,将频率低的字符用较长的编码表示,从而实现对数据的压缩。
在压缩的过程中,利用哈夫曼树可以实现对数据的高效编码和解码。
此外,哈夫曼树还有其他应用,比如在路由表的构建和图像压缩等领域也有广泛应用。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
即 (m-1)×i=t-1
2019/12/26
计算机学院
2
这个定理实质上可以用每局有m个选手参 加的单淘汰制比赛来说明。t个叶表示t个参赛 的选手,i则表示必须安排的总的比赛局数. 每一局由m个参赛者中产生一个优胜者,最后 决出一个冠军。
主要内容
1.完全二叉树 2.Huffman算法
2019/12/26
计算机学院
1
定理11.5
若T是完全m叉树,其树叶数为t,分支点数为 i,则下式成立:
(m-1)×i=t-1
证明 由假设知,该树有i+t个结点。 由定理11.1知,该树的边数为i+t-1。 因为所有结点的出度之和等于边数(握手定
2019/12/26
计算机学院
18
0.8
0.6
0.5 0.5
0.4
0.4 图4
0.1 0.3 1.4
1.9
1.0
0.9
2019/12/26
0.8
0.6
0.5 0.5
0.4
0.4
图5
0.1 0.3
计算机学院
16
3.3 1.9
1.4
1.0
0.9
0.8
0.6
0.5 0.5
0.4
0.4
图6
0.1 0.3
2019/12/26
计算机学院
17
习题十一 14、15、16、18、19、21
9
当i=k+1时,设在完全二叉树T中,v是一个 道路长度为l的分枝点且其两个儿子v1和v2都是 叶,则T–{v1,v2}是含k个分枝点的完全二叉树 T’。
由归纳假设J’=L’+2k, 比较T和T’=T–{v1,v2},可得 J = J’+ 2(I + 1)-l
= J’+l+2, L= L’+l,于是 J = L’+ 2k +l+2 =L+2(k + 1), 即J = L+ 2i。
2019/12/26
计算机学院
13
Huffman算法
给定实数w1,w2, …,wt,且w1≤w2≤…≤wt。 ① 连接权为w1,w2的两片树叶,得一个分支点,其
权为w1+w2; ② 在w1+w2,w3, …,wt中选出两个最小的权,连
接它们对应的顶点(不一定是树叶),得新分 枝点及所带的权; ③ 重复②,直到形成t-1个分支点,t片树叶为止。
2019/12/26
计算机学院
10
例11.8
1
1
2
2
22
3
3
i=5,L=7,J=17
44
2019/12/26
义:设T是有t个叶的二叉树,各叶分别带权
w1,w2, …,wt,各叶的道路长度分别为
l1,l2,…,lt,定义T的权为
W (T )
t
liwi
。
i 1
使W(T)取最小值的T,这个T称为带权
儿子:直接位于给定结点下面的结点,作为 左儿子,对于同一水平线上与给定结点右邻 的结点,作为右儿子,依此类推。
反过来,我们也可以将二叉树还原为有序树。
2019/12/26
计算机学院
6
例11.7
将下图a转化为一棵二叉树。
v1
v1
v1
v2
v3
v4
v7
v5 v6
v8
v9 v10 v11 (a)
2019/12/26
v2
v3
v4
v5 v6v7
v8
v9 v10 v11 (b)
计算机学院
v2
v3
v5
v6 v7
v9 v10 (c)
v4
v8 v11
7
距离、层数、高
v1
v1
v2
v3
v4
v5 v6
v7 v8 v9
v2
v3
v4
v5 v6
v7 v8 v9
v10
v11 (a)
vv1312
v10
v11 (b)
vv1312
定义11.6 在根树中,从树根到任一结点v的道路 长度,称为根到该结点的距离(也称为结点的层 数);称层数相同的结点在同一层上;所有结点 的层数中最大的称为根树的高。
2019/12/26
计算机学院
8
定理11.6 若完全二叉树有i个分支点,且各
分支点的道路长度之和为L,各树叶的道路长度
之和为J,
则
J=L+2×i。
证明:对分支点数目i进行归纳。
当i = 1时,L = 0,J = 2,故J = L + 2i成立。
假设i = k时定理结论成立。
2019/12/26
计算机学院
2019/12/26
计算机学院
4
例11.6
假设有一台计算机,它有一条加法指令,可 计算3个数的和。如果要求9个数x1,x2,x3,x4,x5, x6,x7,x8,x9之和,问至少要执行几次加法指令?
解 用3个结点表示3个数,将表示3个数之和x8的x9 结点作为它们的父结点。这样本问题可理解为 求一个完全三叉树的分支点问题。把9个x6 数x7看 成树叶。由定理11.5知,有(3-1)i =x4 9x-51,得
w1,w2, …,wt 的最优二叉树。
2019/12/26
计算机学院
12
Huffman定理(11.7)
在带权为w1≤w2≤…≤wt的最优二叉树中,必有T 满足: ① 权为w1,w2的两片树叶v1,v2是兄弟; ② 设v1,v2的父亲是v,如果从T中删去v1,v2 ,并 把v改成带权为w1+w2的叶之后的树记为T1,则T1 是带权为w1+w2,w3, …,wt的最优二叉树。
2019/12/26
计算机学院
14
例11.9
给定一组权0.1,0.3,0.4,0.5,0.5, 0.6,0.9,求对应的最优二叉树。
1.0
0.8
0.8
0.5 0.5
0.4
0.4
0.4
0.4
0.4
0.1 0.3
图1
0.1 0.3 图2
0.1 0.3 图3
2019/12/26
计算机学院
15
1.4
1.0
2019/12/26
计算机学院
3
例11.5
设有28盏电灯,拟公用一个电源插座,问 需要多少块具有四插座的接线板? 解: 这个公用插座可以看成是正则四叉树的根 ,每个接线板看成是其它的分枝点,灯泡看成 是叶,则问题就是求总的分枝点的数目。由定 理11.5可以算得i = (28 -1)/3 = 9,因此 ,至少需要9块接线板才能达到目的。
x1ix2= x43。x所4 以x5 至x6少x要7 x执8 行x94次加法x1 指x2令x。3
(a)
(b)
2019/12/26
计算机学院
5
把有序树转换为二叉树
1) 从根开始,保留每个父亲同其最左边儿子的 连线,撤销与别的儿子的连线。
2) 兄弟间用从左向右的有向边连接。 3) 按如下方法确定二叉树中结点的左儿子和右