数据结构最优二叉树
数据结构哈夫曼树和哈夫曼编码权值
数据结构哈夫曼树和哈夫曼编码权值一、引言在计算机领域,数据结构是非常重要的一部分,而哈夫曼树和哈夫曼编码是数据结构中非常经典的部分之一。
本文将对哈夫曼树和哈夫曼编码的权值进行全面评估,并探讨其深度和广度。
通过逐步分析和讨论,以期让读者更深入地理解哈夫曼树和哈夫曼编码的权值。
二、哈夫曼树和哈夫曼编码的基本概念1. 哈夫曼树哈夫曼树,又称最优二叉树,是一种带权路径长度最短的二叉树。
它的概念来源于一种数据压缩算法,可以有效地减少数据的存储空间和传输时间。
哈夫曼树的构建过程是基于给定的权值序列,通过反复选择两个最小权值的节点构建出来。
在构建过程中,需要不断地重排权值序列,直到构建出一个满足条件的哈夫曼树。
2. 哈夫曼编码哈夫曼编码是一种变长编码方式,它利用了哈夫曼树的特点,对不同的字符赋予不同长度的编码。
通过构建哈夫曼树,可以得到一套满足最优存储空间的编码规则。
在实际应用中,哈夫曼编码经常用于数据压缩和加密传输,能够有效地提高数据的传输效率和安全性。
三、哈夫曼树和哈夫曼编码的权值评估1. 深度评估哈夫曼树和哈夫曼编码的权值深度值得我们深入探究。
从构建哈夫曼树的角度来看,权值决定了节点在树中的位置和层次。
权值越大的节点往往位于树的底层,而权值较小的节点则位于树的高层。
这种特性使得哈夫曼树在数据搜索和遍历过程中能够更快地找到目标节点,提高了数据的处理效率。
而从哈夫曼编码的角度来看,权值的大小直接决定了编码的长度。
权值越大的字符被赋予的编码越短,可以有效地减少数据传输的长度,提高了数据的压缩率。
2. 广度评估另哈夫曼树和哈夫曼编码的权值也需要进行广度评估。
在构建哈夫曼树的过程中,权值的大小直接影响了树的结构和形状。
当权值序列较为分散时,哈夫曼树的结构会更加平衡,节点的深度差异较小。
然而,当权值序列的差异较大时,哈夫曼树的结构也会更不平衡,而且可能出现退化现象。
这会导致数据的处理效率降低,需要进行额外的平衡调整。
03、1数据结构第一部分--线性表-树与二叉树
数据结构(一)目录第1章序论 (1)1.1 什么是数据? (1)1.2 什么是数据元素? (1)1.3 什么是数据结构及种类? (1)1.4 数据的逻辑结构 (1)1.5 数据的物理结构 (1)1.6 算法和算法分析 (1)1.7 算法的五个特性 (1)1.8 算法设计的要求 (2)1.9 算法效率的度量 (2)第2章线性表 (3)2.1 线性表举例 (3)2.2 线性表的存储 (4)2.3 线性表-栈 (4)2.4 队列 (4)2.5 双端队列 (6)第3章树和二叉树 (6)3.1 树 (6)3.1.1 树的基本概念 (6)3.1.2 树的常用存储结构 (6)3.1.3 树的遍历 (7)3.2 二叉树 (7)3.2.1 二叉树的基本概念 (7)3.2.2 二叉树与树的区别 (7)3.2.3 树及森林转到二叉树 (7)3.2.4 二叉树的性质 (8)3.2.5 满二叉树 (8)3.2.6 完全二叉树 (8)3.2.7 完全二叉树的性质 (9)3.2.8 二叉树的四种遍历 (9)3.2.9 二叉排序树 (10)3.2.10 平衡二叉树 (11)3.2.11 m阶B-树 (11)3.2.12 最优二叉树 (11)3.2.13 二叉树的存储结构 (12)3.3 广义表 (13)3.4 矩阵的压缩存储 (14)3.4.1 特殊矩阵 (14)3.4.2 压缩存储 (14)第4章历年真题讲解 (15)4.1 2009年上半年 (15)4.2 2009年下半年 (15)4.3 2010年上半年 (15)4.4 2011年上半年 (16)4.5 2011年下半年 (16)4.6 2012年上半年 (17)4.7 2012年下半年 (17)4.8 2013年上半年 (18)4.9 2013年下半年 (18)4.10 2014年上半年 (18)4.11 2014年下半年 (19)4.12 2015年上半年 (19)4.13 2015年下半年 (19)4.14 2016年上半年 (20)第1章序论什么是数据?所有能输入到计算机中并能够被计算机程序处理的符号的总称,它是计算机程序加工的原料。
哈夫曼树_实验报告
一、实验目的1. 理解哈夫曼树的概念及其在数据结构中的应用。
2. 掌握哈夫曼树的构建方法。
3. 学习哈夫曼编码的原理及其在数据压缩中的应用。
4. 提高编程能力,实现哈夫曼树和哈夫曼编码的相关功能。
二、实验原理哈夫曼树(Huffman Tree)是一种带权路径长度最短的二叉树,又称为最优二叉树。
其构建方法如下:1. 将所有待编码的字符按照其出现的频率排序,频率低的排在前面。
2. 选择两个频率最低的字符,构造一棵新的二叉树,这两个字符分别作为左右子节点。
3. 计算新二叉树的频率,将新二叉树插入到排序后的字符列表中。
4. 重复步骤2和3,直到只剩下一个节点,这个节点即为哈夫曼树的根节点。
哈夫曼编码是一种基于哈夫曼树的编码方法,其原理如下:1. 从哈夫曼树的根节点开始,向左子树走表示0,向右子树走表示1。
2. 每个叶子节点对应一个字符,记录从根节点到叶子节点的路径,即为该字符的哈夫曼编码。
三、实验内容1. 实现哈夫曼树的构建。
2. 实现哈夫曼编码和译码功能。
3. 测试实验结果。
四、实验步骤1. 创建一个字符数组,包含待编码的字符。
2. 创建一个数组,用于存储每个字符的频率。
3. 对字符和频率进行排序。
4. 构建哈夫曼树,根据排序后的字符和频率,按照哈夫曼树的构建方法,将字符和频率插入到哈夫曼树中。
5. 实现哈夫曼编码功能,遍历哈夫曼树,记录从根节点到叶子节点的路径,即为每个字符的哈夫曼编码。
6. 实现哈夫曼译码功能,根据哈夫曼编码,从根节点开始,按照0和1的路径,找到对应的叶子节点,即为解码后的字符。
7. 测试实验结果,验证哈夫曼编码和译码的正确性。
五、实验结果与分析1. 构建哈夫曼树根据实验数据,构建的哈夫曼树如下:```A/ \B C/ \ / \D E F G```其中,A、B、C、D、E、F、G分别代表待编码的字符。
2. 哈夫曼编码根据哈夫曼树,得到以下字符的哈夫曼编码:- A: 00- B: 01- C: 10- D: 11- E: 100- F: 101- G: 1103. 哈夫曼译码根据哈夫曼编码,对以下编码进行译码:- 00101110111译码结果为:BACGACG4. 实验结果分析通过实验,验证了哈夫曼树和哈夫曼编码的正确性。
数据结构之二叉树(BinaryTree)
数据结构之⼆叉树(BinaryTree)⽬录导读 ⼆叉树是⼀种很常见的数据结构,但要注意的是,⼆叉树并不是树的特殊情况,⼆叉树与树是两种不⼀样的数据结构。
⽬录 ⼀、⼆叉树的定义 ⼆、⼆叉树为何不是特殊的树 三、⼆叉树的五种基本形态 四、⼆叉树相关术语 五、⼆叉树的主要性质(6个) 六、⼆叉树的存储结构(2种) 七、⼆叉树的遍历算法(4种) ⼋、⼆叉树的基本应⽤:⼆叉排序树、平衡⼆叉树、赫夫曼树及赫夫曼编码⼀、⼆叉树的定义 如果你知道树的定义(有限个结点组成的具有层次关系的集合),那么就很好理解⼆叉树了。
定义:⼆叉树是n(n≥0)个结点的有限集,⼆叉树是每个结点最多有两个⼦树的树结构,它由⼀个根结点及左⼦树和右⼦树组成。
(这⾥的左⼦树和右⼦树也是⼆叉树)。
值得注意的是,⼆叉树和“度⾄多为2的有序树”⼏乎⼀样,但,⼆叉树不是树的特殊情形。
具体分析如下⼆、⼆叉树为何不是特殊的树 1、⼆叉树与⽆序树不同 ⼆叉树的⼦树有左右之分,不能颠倒。
⽆序树的⼦树⽆左右之分。
2、⼆叉树与有序树也不同(关键) 当有序树有两个⼦树时,确实可以看做⼀颗⼆叉树,但当只有⼀个⼦树时,就没有了左右之分,如图所⽰:三、⼆叉树的五种基本状态四、⼆叉树相关术语是满⼆叉树;⽽国际定义为,不存在度为1的结点,即结点的度要么为2要么为0,这样的⼆叉树就称为满⼆叉树。
这两种概念完全不同,既然在国内,我们就默认第⼀种定义就好)。
完全⼆叉树:如果将⼀颗深度为K的⼆叉树按从上到下、从左到右的顺序进⾏编号,如果各结点的编号与深度为K的满⼆叉树相同位置的编号完全对应,那么这就是⼀颗完全⼆叉树。
如图所⽰:五、⼆叉树的主要性质 ⼆叉树的性质是基于它的结构⽽得来的,这些性质不必死记,使⽤到再查询或者⾃⼰根据⼆叉树结构进⾏推理即可。
性质1:⾮空⼆叉树的叶⼦结点数等于双分⽀结点数加1。
证明:设⼆叉树的叶⼦结点数为X,单分⽀结点数为Y,双分⽀结点数为Z。
数据结构哈夫曼树和哈夫曼编码
最优二叉树的定义
结点的路径长度定义为:
从根结点到该结点的路径上分支的数目。
树的路径长度定义为:
A
树中每个结点的路径长度之和。 B C E
D
树的路径长度为5
最优二叉树的定义
树的带权路径长度定义为:
哈夫曼树与哈夫曼编码
1.最优二叉树的定义 2.如何构造最优二叉树 3.哈夫曼编码
编码
假设要将一段文字“ABAADBCACB”由甲方传给乙方
编码:用二进制数表示字符
ABCD
00 01 10 11
特点:等长编码
ABAADBCACB 00010000110110001001 总的编码长度是20位
前缀编码
哈夫曼树
2.在 F 中选取其根结点的权值为最小的两 棵二叉树,分别作为左、右子树构造一棵新的 二叉树,并置这棵新的二叉树根结点的权值为 其左、右子树根结点的权值之和;
哈夫曼树
3.从F中删去这两棵树,同时将刚生成的新 树加入到F中;
4.重复 (2) 和 (3) 两步,直至 F 中只含
一棵树为止。
哈夫曼树
1) 5
6
2
2) 6
9
7
9
7
7
3) 9
2
5
7
13
6
7
2
5
哈夫曼树
4)
13
6
7
2
5
16
7
9
5)பைடு நூலகம்
29
13
16
6
7
7
9
2
数据结构:二叉树、平衡二叉树、红黑树详解
数据结构:⼆叉树、平衡⼆叉树、红⿊树详解⼀、⼆叉树(binary tree)指每个节点最多含有两个⼦树的树结构。
时间复杂度为O(log N),在退化成链表的情况下时间复杂度为O(N)。
特点:1.所有节点最多拥有两个⼦节点;2.节点的左⼦树只包含⼩于当前根节点的数,节点的右⼦树只包含⼤于当前根节点的数。
缺点:只会以我们第⼀次添加的节点为根节点,如果后⾯添加的节点值都⼤于或⼩于根节点的值,在这种情况下会退化成链表。
⼆、平衡⼆叉树(Balanced Binary Tree)⼜称为AVL树,具有⼆叉树的全部特性,解决⼆叉树退化成链表情况的问题,每个节点的左⼦树和右⼦树的⾼度之差不会超过1,AVL树是严格的平衡⼆叉树,追求完全平衡,⽐较严格。
缺点:由于要求每个节点的左⼦树和右⼦树⾼度之差不超过1,这个要求⾮常严格,追求完全平衡,这就导致了在频繁插⼊和删除的场景中,可能就会导致AVL树失去平衡,AVL树就需要频繁的通过左旋右旋使其重新达到平衡,这时就会时得其性能⼤打折扣。
三、红⿊树和AVL树相⽐,红⿊树放弃追求完全平衡,⽽是追求⼤致平衡,保证每次插⼊节点最多只需要三次旋转就能达到平衡,维持平衡的耗时较少,实现起来也更为简单,它的旋转次数较少,对于频繁插⼊和删除操作的场景,相⽐AVL树,红⿊树更具优势。
特征:1.红⿊树是也是平衡⼆叉树实现的⼀种⽅式2.节点只能是⿊⾊或者红⾊,root根节点⼀定是⿊⾊3.新增时默认新增的节点是红⾊,不允许两个红⾊节点相连4.红⾊节点的两个⼦节点⼀定是⿊⾊红⿊树变换规则三种规则:1.改变节点颜⾊2.左旋转3.右旋转变⾊的情况:当前节点的⽗亲节点是红⾊,并且它的祖⽗节点的另外⼀个⼦节点(叔叔节点)也是红⾊:以当前节点为指针进⾏操作1.将⽗亲节点变为⿊⾊2.将叔叔节点变为⿊⾊3.将祖⽗节点变为红⾊4.再把指针定义到祖⽗节点进⾏旋转操作左旋转:当⽗亲节点为红⾊情况,叔叔节点为⿊⾊情况,且当前节点是右⼦树,左旋转以⽗节点作为左旋。
计算机数据结构知识点梳理 哈夫曼(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};
数据结构哈夫曼树和哈夫曼编码PPT课件
C
AB
AC
BC
ABC
第27页/共55页
回朔策略—求幂集
000
000
100
000
010
100
110
000
001
010
011 100 101 110
111
第28页/共55页
回朔策略—求幂集
void powerSet(int num){ if (num<=len-1) { for (int i=0; i<2; i++){ if (i = = 0) mask[num]=1; else mask[num]=0; powerSet(num+1);} } else{ for (int j=0; j<len; j++){ if (mask[j]==1) printf("%c",set[j]);} printf("\n");}
}
第29页/共55页
回朔策略—求幂集
int len=3; int mask[]={0,0,0}; char set[]={'A','B','C'}; int main(int argc, char* argv[]) {
powerSet(0); return 0; }
第30页/共55页
章末复习
1. 熟练掌握二叉树的结构特性,了解相应的证 明方法。 2. 熟悉二叉树的各种存储结构的特点及适用范 围。 3. 遍历二叉树是二叉树各种操作的基础。实现 二叉树遍历的具体算法与所采用的存储结构有 关。掌握各种遍历策略的递归算法,灵活运用 遍历算法实现二叉树的其它操作。层次遍历是 按另一种搜索策略进行的遍历。
【数据结构】二叉树
【数据结构】⼆叉树【⼆叉树】 ⼆叉树是最为简单的⼀种树形结构。
所谓树形结构,其特征(部分名词的定义就不明确给出了,毕竟不是学术⽂章。
)在于: 1. 如果是⾮空的树形结构,那么拥有⼀个唯⼀的起始节点称之为root(根节点) 2. 除了根节点外,其他节点都有且仅有⼀个“⽗节点”;除此外这些节点还都可以有0到若⼲个“⼦节点” 3. 树中的所有节点都必须可以通过根节点经过若⼲次后继操作到达 4. 节点之间不会形成循环关系,即任意⼀个节点都不可能从⾃⾝出发,经过不重复的径路再回到⾃⾝。
说明了树形结构内部蕴含着⼀种“序”,但是不是线性表那样的“全序” 5. 从树中的任意两个节点出发获取到的两个任意⼦树,要不两者⽆交集,要不其中⼀者是另⼀者的⼦集 限定到⼆叉树,⼆叉树就是任意⼀个节点⾄多只能有两个⼦节点的树形结构。
也就是说,某个节点的⼦节点数可以是0,1或2。
由于可以有两个⼦节点,所以区别两个⼦节点可以将其分别定义为左⼦节点和右⼦节点。
但是需要注意的是,若⼀个节点只有⼀个⼦节点,那么也必须明确这个⼦节点是左⼦节点还是右⼦节点。
不存在“中⼦节点”或者“单⼦节点”这种表述。
由于上述规则对所有节点都⽣效,所以⼆叉树也是⼀个递归的结构。
事实上,递归就是⼆叉树⼀个⾮常重要的特点,后⾯还会提到很多通过递归的思想来建⽴的例⼦。
对于左⼦节点作为根节点的那颗⼆叉树被称为相对本节点的左⼦树,右⼦树是同理。
■ 基本概念 空树 不包含任何节点的⼆叉树,连根节点也没有 单点树 只包含⼀个根节点的⼆叉树是单点树 ⾄于兄弟关系,⽗⼦关系,长辈后辈关系是⼀⾔既明的就不说了。
树中没有⼦节点的节点被称为树叶(节点),其余的则是分⽀节点。
⼀个节点的⼦节点个数被称为“度数”。
正如上所说,⼆叉树任意节点的度数取值可能是0,1或2。
节点与节点之间存在关联关系,这种关联关系的基本长度是1。
通过⼀个节点经过若⼲个关联关系到达另⼀个节点,经过的这些关联关系合起来被称为⼀个路径。
数据结构二叉树知识点总结
数据结构二叉树知识点总结二叉树是指每个节点最多有两个子节点的树结构。
它是一种重要的数据结构,在算法和程序设计中被广泛应用。
下面是对二叉树的主要知识点进行详细总结。
1.二叉树的基本概念:-树节点:树的基本单元,包含数据项(节点值)和指向其他节点的指针。
-根节点:树的第一个节点。
-叶节点(又称为终端节点):没有子节点的节点。
-子节点:一些节点的下一级节点。
-父节点:一些节点的上一级节点。
-兄弟节点:拥有同一父节点的节点。
-深度:从根节点到当前节点的路径长度。
-高度:从当前节点到最远叶节点的路径长度。
2.二叉树的分类:-严格二叉树:每个节点要么没有子节点,要么有两个子节点。
-完全二叉树:除了最后一层外,其他层的节点数都达到最大,并且最后一层的节点依次从左到右排列。
-满二叉树:每个节点要么没有子节点,要么有两个子节点,并且所有叶节点都在同一层上。
-平衡二叉树:任意节点的两棵子树的高度差不超过13.二叉树的遍历:-前序遍历:根节点->左子树->右子树。
递归实现时,先访问当前节点,然后递归遍历左子树和右子树。
-中序遍历:左子树->根节点->右子树。
递归实现时,先递归遍历左子树,然后访问当前节点,最后递归遍历右子树。
-后序遍历:左子树->右子树->根节点。
递归实现时,先递归遍历左子树,然后递归遍历右子树,最后访问当前节点。
-层序遍历:从上到下,从左到右依次访问每个节点。
使用队列实现。
4.二叉查找树(BST):-二叉查找树是一种有序的二叉树,对于树中的每个节点,其左子树的节点的值都小于当前节点的值,右子树的节点的值都大于当前节点的值。
-插入操作:从根节点开始,递归地比较要插入的值和当前节点的值,根据比较结果向左或向右移动,直到找到插入位置为止。
-查找操作:从根节点开始,递归地比较要查找的值和当前节点的值,根据比较结果向左或向右移动,直到找到目标节点或到叶节点。
-删除操作:有三种情况:-被删除节点是叶节点:直接将其删除。
数据结构之二叉树PPT
2015年5月16日星期六
12
二叉树性质
3. 任何一颗二叉树,度为0的结点比度为2的结点 多一个。
证明:设有n个结点的二叉树的度为0、1、2的结点数分 别为=n0,n1,n2,n=n0 +n1 +n2 (公式1) 设边数为e。因为除根以外,每个结点都有一条边进入, 故n=e+1。 由于这些边是有度为1和2的结点射出的,因此e=n1+ 2*n2,于是n=e+1= n1 +2*n2 +1(公式2) 因此由公式(1)(2)得 n0+n1+n2=n1+2*n2+1 即n0 =n2 +1
}
2015年5月16日星期六
21
由二叉树的先序和中序序列建树
仅知二叉树的先序序列“abcdefg” 不能唯 一确定一棵二叉树,
如果同时已知二叉树的中序序列“cbdaegf”,
则会如何?
二叉树的先序序列
二叉树的中序序列
2015年5月16日星期六
根 左子树 右子树 左子树 根 右子树
22
例如:
a b c d e f g c b d a e g f
2015年5月16日星期六
10
二叉树性质
2、满二叉树定理的推论: 一棵非空二叉树空子树 的数目等于其结点数目加1。
证明1:设二叉树T,将其所有空子树换成叶结点,把新 的二叉树记为T‘。所有原来树T的结点现在是树T’的分支 结点。 根据满二叉树定理,新添加的叶结点数目等于树T的 结点数目加1, 而每个新添加的叶结点对应树T的一棵空子树,因此 树T中空子树的数目等于树T中结点数目加1。
29
顺序存储
非完全二叉树在置空值而转换为完全二叉树存储 CEDJFX//K/G/I/////L
数据结构——哈夫曼(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}对应的哈夫曼树。
⾄此,应该堆哈夫曼树的概念有了⼀定的了解了,下⾯看看如何去构造⼀棵哈夫曼树。
数据结构课程设计 哈夫曼树
数据结构课程设计哈夫曼树数据结构课程设计 - 哈夫曼树一、引言哈夫曼树(Huffman Tree)是一种经典的数据结构,常被用于数据压缩和编码中。
它是一种特殊的二叉树,具有最优的前缀编码性质。
本文将详细介绍哈夫曼树的定义、构建方法以及应用场景。
二、哈夫曼树的定义哈夫曼树是一种满足以下条件的二叉树:1. 所有的叶子节点都带有权值;2. 没有度为1的节点;3. 任意两个叶子节点的路径长度不相同。
三、哈夫曼树的构建方法1. 构建哈夫曼树的基本思想是将权值较小的节点放在较低的层次,权值较大的节点放在较高的层次;2. 首先,根据给定的权值集合,将每一个权值看做一个独立的节点;3. 然后,选择两个权值最小的节点,将它们合并为一个新节点,并将新节点的权值设置为这两个节点的权值之和;4. 重复上述步骤,直到只剩下一个节点,即为哈夫曼树的根节点。
四、哈夫曼编码哈夫曼编码是一种变长编码方式,用于将字符转换为二进制编码。
它的特点是没有编码冗余,即每一个字符的编码都不是其他字符编码的前缀。
这种编码方式可以大幅度减小数据的存储空间和传输带宽。
五、哈夫曼树的应用场景1. 数据压缩:哈夫曼树可以根据字符浮现的频率构建最优的编码方式,从而实现数据的高效压缩;2. 文件压缩:将文件中的字符转换为哈夫曼编码,可以大幅度减小文件的大小;3. 图象压缩:将图象中的像素值转换为哈夫曼编码,可以实现图象的无损压缩;4. 视频压缩:将视频中的帧数据转换为哈夫曼编码,可以减小视频文件的大小。
六、哈夫曼树的时间复杂度和空间复杂度1. 构建哈夫曼树的时间复杂度为O(nlogn),其中n为权值的个数;2. 哈夫曼编码的时间复杂度为O(n),其中n为字符的个数;3. 哈夫曼树的空间复杂度为O(n),其中n为权值的个数。
七、总结哈夫曼树是一种重要的数据结构,具有广泛的应用场景。
通过构建最优的编码方式,可以实现高效的数据压缩和编码。
掌握哈夫曼树的定义、构建方法以及应用场景,对于数据结构课程的学习和实践具有重要意义。
PTA数据结构哈夫曼树与哈夫曼编码
PTA数据结构哈夫曼树与哈夫曼编码⽂章⽬录题⽬描述题⽬背景:介绍什么是哈夫曼树和哈夫曼编码, 不影响做题哈夫曼树(Huffman Tree)⼜称最优⼆叉树,是⼀种带权路径长度最短的⼆叉树。
所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。
树的路径长度是从树在数据通信中,需要将传送的⽂字转换成⼆进制的字符串,⽤0,1码的不同排列来表⽰字符。
例如,需传送的报⽂为“AFTER DATA EAR ARE ART AREA”,这⾥⽤到的字符集为“A,E,R,T,F,D”,各字母出现的次数为{8,4,5,3,1,1}。
现要为使不等长编码为前缀编码(即要求⼀个字符的编码不能是另⼀个字符编码的前缀),可⽤字符集中的每个字符作为叶⼦结点⽣成⼀棵编码⼆叉树,为了获得传送报⽂的最短长度,可将每个字符的出现频率作为字符结点的权值赋予该结点上,显然字使⽤本题要求从键盘输⼊若⼲电⽂所⽤符号及其出现的频率,然后构造哈夫曼树,从⽽输出哈夫曼编码。
注意:为了保证得到唯⼀的哈夫曼树,本题规定在构造哈夫曼树时,左孩⼦结点权值不⼤于右孩⼦结点权值。
如权值相等,则先选优先级队列中先出队的节点。
编码时,左分⽀取“0”,右分⽀取“1”。
输⼊格式输⼊有3⾏第1⾏:符号个数n(2~20)第2⾏:⼀个不含空格的字符串。
记录着本题的符号表。
我们约定符号都是单个的⼩写英⽂字母,且从字符‘a’开始顺序出现。
也就是说,如果 n 为 2 ,则符号表为 ab;如果 n 为 6,则符号为 abcdef;以此类推。
第3⾏:各符号出现频率(⽤乘以100后的整数),⽤空格分隔。
输出格式先输出构造的哈夫曼树带权路径长度。
接下来输出n⾏,每⾏是⼀个字符和该字符对应的哈夫曼编码。
字符按字典顺序输出。
字符和哈夫曼编码之间以冒号分隔。
样例输⼊:8abcdefgh5 29 7 8 14 23 3 11输出:271a:0001b:10c:1110d:1111e:110f:01g:0000h:001⼀点说明关于题⽬描述中的"如权值相等,则先选优先级队列中先出队的节点"可以参考上图, 权值为7的节点选择了权值为8的叶⼦节点, ⽽不是权值为8的⼦树感觉题⽬想表达的意思是, 若权值相等,则先选优先级队列中先⼊队的节点(如有错误, 望指正)想法利⽤优先队列维护⼩根堆(因为建树时,要选两个权值最⼩的),利⽤哈夫曼算法建树,再根据所建哈夫曼树,利⽤深搜回溯,得到各个字符的哈夫曼编码和树的带权路径长度实现#include <cstdio>#include <iostream>#include <string>#include <queue>#include <vector>using namespace std;struct node{int weight;char ch = 'z' + 1; // 这样在优先队列⾃定义排序时, 可以做到权值相等,则先选优先级队列中先出队的节点node *lchild, *rchild;};// ⾃定义优先队列的排序⽅式, 权值⼩优先, 权值相等,则先选优先级队列中先出队的节点struct cmp{bool operator() (node* a, node* b){if(a->weight == b->weight)return a->ch > b->ch;return a->weight > b->weight;}};int n, WPL; // n:结点数 WPL:树的带权路径长度(⾮叶⼦节点的权值和)string str;priority_queue<node, vector<node*>, cmp> q; //vector<char> ans[100]; // 存放哈夫曼编码vector<char> code; // ⽤于深搜得到哈夫曼编码node* createTree() // 建⽴哈夫曼树{node* r;while(!q.empty()){if(q.size() == 1){node* a = q.top();q.pop();r = a;break;}else{node* a = q.top();q.pop();node* b = q.top();q.pop();node* c = new node();c->weight = a->weight + b->weight;c->lchild = a;c->rchild = b;r = c;q.push(c);}}return r;}void print() // 输出前缀编码{cout << WPL << endl;for(int i=0; i<n; i++){cout << str[i] << ":";int index = str[i] - 'a';for(int j=0; j<ans[index].size(); j++)cout << ans[index][j];cout << endl;}}void dfs(node* root) // 深搜回溯得到哈夫曼编码和树的带权路径长度{if(root->lchild != NULL || root->rchild != NULL)WPL += root->weight; // WPL即⾮叶⼦节点的权值之和if(root->lchild == NULL && root->rchild == NULL){char ch = root->ch;ans[ch-'a'] = code; // 根据叶⼦节点的字符, 判断是谁的哈夫曼编码return;}if(root->lchild != NULL){code.push_back('0');dfs(root->lchild);code.pop_back(); // 回溯}if(root->rchild != NULL){code.push_back('1');dfs(root->rchild);code.pop_back(); // 回溯}return;}int main(){cin >> n;cin >> str;for(int i=0; i<n; i++) // 读⼊各节点的权值, 利⽤优先队列维护⼩根堆, 便于建树{node* temp = new node(); // 不要忘记给指针分配空间cin >> temp->weight;temp->ch = str[i];temp->lchild = temp->rchild = NULL;q.push(temp);}node* root = createTree(); // 建⽴哈夫曼树dfs(root); // 回溯得到哈夫曼编码及WPLprint();return 0;}。
数据结构——霍夫曼树及题目场景应用
数据结构——霍夫曼树及题⽬场景应⽤什么是霍夫曼树霍夫曼树是⼆叉树的⼀种特殊形式,⼜称为最优⼆叉树,其主要作⽤在于数据压缩和编码长度的优化。
给定n个权值作为n个叶⼦结点,构造⼀棵⼆叉树,若带权路径长度达到最⼩,称这样的⼆叉树为最优⼆叉树,也称为霍夫曼树(Huffman Tree)。
霍夫曼树的构造思路若要使得带权外路径长度最⼩,可以将权值⼤的节点尽量靠近根节点,这样路径短⼀些;⽽权值⼩的节点可以适当远离根节点,因为权值⼩,外路径稍微长⼀点也没事。
应⽤场景霍夫曼编码霍夫曼编码是⼀种基于最⼩冗余编码的压缩算法。
最⼩冗余编码是指,如果知道⼀组数据中符号出现的频率,就可以⽤⼀种特殊的⽅式来表⽰符号从⽽减少数据需要的存储空间。
⼀种⽅法是使⽤较少的位对出现频率⾼的符号编码,⽤较多的位对出现频率低的符号编码。
我们要意识到,⼀个符号不⼀定必须是⽂本字符,它可以是任何⼤⼩的数据,但往往它只占⼀个字节。
算法题应⽤霍夫曼树的特性除了压缩,还可以⽤于⼀些关于最⼩代价问题的决策上。
例如:⼀个⽼⽊匠,有若⼲段长短不⼀的⽊头,他想把这些⽊头全部拼成⼀根,每次拼接耗费的体⼒是当前拼接的两段⽊头的长度,问⽼⽊匠最⼩花费多少体⼒。
代码实现1. 利⽤优先队列存储节点,保证队列中的节点值是有序的;2. 每次获取队列中的两个最⼩值,然后⽤这两个节点的和构造⼀个新的节点作为它们的⽗节,然后⼦节点出队,⽗节点⼊队;3. 循环这个过程,直到队列中只有⼀个节点为⽌,返回这个节点即可。
TreeNode hfmTree(int[] w){// 将所有节点存⼊优先队列,按照权值递增排序PriorityQueue<TreeNode> queue = new PriorityQueue<>(w.length, (a, b) -> a.val - b.val);for(int i=0; i<w.length; i++){queue.offer(new TreeNode(w[i]));}// 构造哈夫曼树while( queue.size() > 1 ){// 弹出最⼩的两个节点TreeNode node1 = queue.poll();TreeNode node2 = queue.poll();// 构造⽗节点TreeNode father = new TreeNode(node1.val + node2.val);father.left = node1;father.right = node2;// ⽗节点⼊队queue.offer( father );}return queue.poll();}。
数据结构判断题
数据结构判断题数据结构是计算机科学中非常重要的一个概念,它描述了数据之间的关系和组织方式。
在编程和算法设计中,对于数据结构的理解和运用至关重要。
以下是一些关于数据结构的判断题,旨在匡助您巩固对数据结构的理解和应用。
1. 栈和队列都是线性数据结构。
答案:正确解析:栈和队列都是一种特殊的线性数据结构,它们都是按照先进后出(LIFO)或者先进先出(FIFO)的原则进行操作。
2. 二叉树可以是空树。
答案:正确解析:二叉树是一种树状结构,它可以为空树,即不包含任何节点。
3. 哈希表的查找操作的时间复杂度是O(1)。
答案:正确解析:哈希表通过将关键字映射到一个固定的位置来进行查找,因此查找操作的时间复杂度是常数级别的,即O(1)。
4. 链表的插入和删除操作的时间复杂度都是O(1)。
答案:错误解析:链表的插入和删除操作的时间复杂度取决于插入或者删除的位置,如果是在链表的开头或者结尾进行操作,时间复杂度是O(1),但如果是在链表中间进行操作,时间复杂度是O(n),其中n是链表的长度。
5. 堆排序是一种稳定的排序算法。
解析:堆排序是一种不稳定的排序算法,因为在堆的调整过程中,相同元素的相对位置可能会发生改变。
6. 广度优先搜索算法可以用来求解最短路径问题。
答案:正确解析:广度优先搜索算法可以用来求解无权图的最短路径问题,它从起始节点开始,逐层遍历图,直到找到目标节点或者遍历完所有节点。
7. AVL树是一种自平衡的二叉搜索树。
答案:正确解析:AVL树是一种自平衡的二叉搜索树,它通过旋转操作来保持树的平衡,使得树的高度始终保持在一个较小的范围内,从而提高搜索、插入和删除操作的效率。
8. 图可以用邻接矩阵或者邻接表来表示。
答案:正确解析:图可以用邻接矩阵或者邻接表来表示,邻接矩阵适合于稠密图,邻接表适合于稀疏图。
9. 二叉搜索树的中序遍历结果是有序的。
答案:正确解析:二叉搜索树的中序遍历结果是按照节点的值从小到大罗列的,因此是有序的。
哈夫曼树算法
哈夫曼树算法
哈夫曼树算法是一种常用的树形数据结构,也被称为最优二叉树算法。
它是由美国计算机科学家David A. Huffman于1952年发明的,用于数据压缩和编码的问题中。
哈夫曼树算法的基本思想是,将出现频率较高的字符编码为较短的二进制序列,而将出现频率较低的字符编码为较长的二进制序列,以达到压缩数据的目的。
这种编码方式被称为哈夫曼编码。
哈夫曼树算法的构建过程是从数据源中选出频率最小的两个数据,将它们合并成一个新的节点,其权重为这两个数据的权重之和。
然后再将这个新节点加入到数据源中,重复这个过程,直到数据源中只剩下一个节点,这个节点就是哈夫曼树的根节点。
哈夫曼树的权重值是所有叶子节点的权重乘以它们的深度之和,也是数据压缩的效率指标。
哈夫曼树算法可以用来解决许多经典的问题,如最优合并策略、最优缩短编码长度等。
总之,哈夫曼树算法是一种非常重要的算法,对于数据压缩和编码问题有着广泛的应用。
它的实现方法也比较简单,但是需要对数据源进行一定的分析和预处理,以得到最优的数据压缩效果。
- 1 -。
最优二叉树规则
最优二叉树规则最优二叉树是一种常见的数据结构,也被称为霍夫曼树。
它的最主要的特点就是能够在动态数据中快速定位元素的位置,从而进行高效的操作。
接下来,我们将分步骤阐述“最优二叉树规则”。
一、概念介绍最优二叉树是一种满足加权路径长度最小的二叉树。
其中,加权路径长度定义为树中所有叶节点的深度乘以其权重,并且具有公式WPL= ∑(i=1,n) w(i) * d(i),其中w(i) 代表叶子节点的权重,d(i)代表叶子节点深度。
二、构建步骤1.首先将所有节点按照权重从大到小排序,构造一个包含所有节点的森林,每个节点在单独的树上。
2.从森林中选取两棵根节点权重最小的树进行合并,节点之间添加一个新的父节点,并将权重设置为子节点权重之和。
3.将新生成的树插入到森林中,删除原有两个节点的树。
4.重复上述合并操作,直到森林中只有一棵树,此时形成的树就是最优二叉树。
三、示例分析例如,现在有集合S={A:7,B:8,C:2,D:5},每个元素及其权重如表所示,我们将使用以上核心步骤来构建其最优二叉树。
1.首先将所有节点按照权重从大到小排序。
C:2,D:5,A:7,B:82.从森林中选取两棵根节点权重最小的树进行合并。
C:2------>----------(1)---------D:5------> A:7--------(3)---------B:8-----3.继续合并子树,形成最底层的新树。
C:2-------> (1)-------(4)---------------(2)--------- A:7-------- B:8--------D:5-------- C:2-------- 最终,我们成功地构建了一个最优二叉树,其中所有的元素在树中的分布符合“贪心算法”的规律,保证了在查找、插入、删除元素时的效率。
总结:最优二叉树规则包含了四个关键步骤:排序,树的合并,新父节点的添加,以及循环合并。
数据结构 第六章-树
20
A B C D
E
F
G H
I J
A
E F H
G
B C
D A
I J
A
B C F
E H
G
B C D F
E G H I J
21
I
D
J
5. 二叉树转换成树和森林
二叉树转换成树 1. 加线:若p结点是双亲结点的左孩子,则将p的右孩 子,右孩子的右孩子,……沿分支找到的所有右孩 子,都与p的双亲用线连起来 2. 抹线:抹掉原二叉树中双亲与右孩子之间的连线 3. 调整:将结点按层次排列,形成树结构7Fra bibliotek6.3.2
树和森林的存储结构
树的存储结构有很多,既可以采用顺序存储结构, 也可以采用链式存储结构。但无论采用哪种存储方式, 都要求存储结构不仅能存储各结点本身的数据信息,还 要能惟一地反映树中各结点之间的逻辑关系。 双亲表示法 孩子链表表示法 孩子兄弟表示法
8
1.双亲表示法 除根外,树中的每个结点都有惟一的一个双亲结点,所以可以用一 组连续的存储空间存储树中的各结点。一个元素表示树中一个结点, 包含树结点本身的信息及结点的双亲结点的位臵。 A B E F C G H D I
}CTBox;
//树结构 typedef struct {CTBox nodes[MAX_TREE_SIZE]; int n, r; }Ctree
12
3. 孩子-兄弟表示法(树的二叉链表)
孩子兄弟表示法用二叉链表作为树的存储结构。将树中的多支关系用 二叉链表的双支关系体现。 ※ 结点的左指针指向它的第一个孩子结点
//孩子结点结构 typedef struct CTNode
1 2 3 4 5 6
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
① 用字符ci作为叶子,wi 做为叶子ci的权,构造一棵哈夫曼树,并 将树中左分支和右分支分别标记为0和1; ② 将从根到叶子的路径上的标号依次相连,作为该叶子所表示字符的 编码。该编码即为最优前缀码(也称哈夫曼编码)。
(3) 哈夫曼树求得编码为最优前缀码的原因 ① 每个叶子字符ci的码长恰为从根到该叶子的路径长度li,平均码 长(或文件总长)又是二叉树的带权路径长度WPL。而哈夫曼树是WPL最小 的二叉树,因此编码的平均码长(或文件总长)亦最小。 ② 树中没有一片叶子是另一叶子的祖先,每片叶子对应的编码就不可 能是其它叶子编码的前缀。即上述编码是二进制的前缀码。
可以验证,该编码是前缀编码,若一段程序有1000条指令,其中A大约
有400条,B大约有300条,C大约有50条,D大约有40,E大约有30条,F
大约有30条。对于定长编码,该段程序的总位数大约为3×1000=3000.
采用哈夫曼编码后,该段程序的总位数大约为
1×400+2×300+3×150+5×(50+40+30+30)=2200.可见,哈夫曼编码
//由n个结点的哈夫曼树haffTree构造哈夫曼编码haffCode {
00
D
01
E
000
F
001
这样虽然可以使得程序的总位数达到 G
010
最小,但机器却无法解码。例如对编码串0010110该怎么识别呢?第一
个0可以识别A,也可以识别与第二个0组成的串00一起被识别为C,还可
以将前三位识别为F,这样一来,这个编码串就有多种译法。因此,若
要设计变长编码,则这种编码必须满足这样一个条件:任意一个编码不
能成为其它任意编码的前缀。我们把这个条件的编码叫做前缀编码。
根据以上描述,利用哈夫曼算 法,我们可以设计出最优的前缀编
指令 A
编码 0
码。首先,我们以每条指令的使用频 B
率为权值构造哈夫曼树,如图(三)所
示
C
0.60
D
0.30
1.00
E
0.30
0.15
F
0.40
0.15
G
0.09
0.06
0.04
0.05
} else if(haffTree[j].weight < m2 && haffTree[j].flag == 0)
{ m2 = haffTree[j].weight; x2 = j;
} } //将找出的两棵权值最小的子树合并为一棵子树
haffTree[x1].parent = n+i; haffTree[x2].parent = n+i; haffTree[x1].flag = 1; haffTree[x2].flag = 1; haffTree[n+i].weight = haffTree[x1].weight+haffTree[x2].weight; haffTree[n+i].leftChild = x1; haffTree[n+i].rightChild = x2; } } 哈夫曼编码算法如下: void HaffmanCode(HaffNode haffTree[], int n, Code haffCode[])
7 3 1
5
7 2
3 5 1 7
5
1 3 1
3
7 5
7 1 3 5
(a)
(b)
(c)
(d)
(e)
图(二 ) 具有相同叶子结点和不同带权路径长度的二叉树
由此可见,由相同权值的一组叶子结点所构成的二叉树有不同的形 态和不同的带权路径长度,那么如何找到带权路径长度最小的二叉树 (即哈夫曼树)呢?根据哈夫曼树的定义,一棵二叉树要使其WPL值最 小,必须使权值越大的叶结点越靠近根结点,而权值越小的叶结点越远 离根结点。哈夫曼(Haffman)依据这一特点于1952年提出了一种方 法,这种方法的基本思想是:
d) 重复(b)(c)两步,当F中只剩下一棵二叉树时,这棵二叉 树便是所要建立的哈夫曼树。
由于这种算法是哈夫曼最早提出的,所以将最优二叉树称为哈夫曼 树。
(2) 根据最优二叉树构造哈夫曼编码
哈夫曼树被广泛应用在各种技术中,其中最典型的就是在编码技术上
的应用。利用哈夫曼树很容易求出给定字符集及其概率(或频度)分布的
a) 由给定的n个权值{W1,W2,…,Wn}构造n棵只有一个叶结点 的二叉树,从而得到一个二叉树的集合F={T1,T2,…, Tn};
b) 在F中选取根结点的权值最小和次小的两棵二叉树作为左、右 子树构造一棵新的二叉树,这棵新的二叉树根结点的权值为 其左、右子树根结点权值之和;
c) 在集合F中删除作为左、右子树的两棵二叉树,并将新建立的 二叉树加入到集合F中;
中虽然大部分编码的长度大于定长编码的长度3,却使得程序的总位数
变小了。可以算出该哈夫曼的平均码长为
li×wi =1×0.40+2×0.30+3×0.15+5×0.05+5×0.40+5×0.30+5×0.30=2.2
7
∑
i=1
根据上述例子我们可以总结出,利用哈夫曼树获得哈夫曼编码,即最优 前缀编码的具体操做:
(4) 哈夫曼编码的算法 思路:给定字符集的哈夫曼树生成后,求哈夫曼编码的具体实现过程 是:依次以叶子C[i](0≤i≤n-1)为出发点,向上回溯至根为止。上溯 时走左分支则生成代码0,走右分支则生成代码1。
注意: ①由于生成的编码与要求的编码反序,将生成的代码先从后往前依次存 放在一个临时向量中,并设一个指针start指示编码在该向量中的起始 位置(start初始时指示向量的结束位置)。 ②当某字符编码完成时,从临时向量的start处将编码复制到该字符相 应的位串bits中即可。 ③因为字符集大小为n,故变长编码的长度不会超过n,加上一个结束 符'\0',bits的大小应为n+1。
2、 最优二叉树原理分析
(1) 最优二叉树的基本概念
最优二叉树,也称哈夫曼(Haffman)树,是指对于一组带有确定权 值的叶结点,构造的具有最小带权路径长度的二叉树。那么什么是二叉 树的带权路径长度呢?
如果设二叉树具有n个带权值的叶结点,那么从根结点到各个叶结 点的路径长度与相应结点权值的乘积之和叫做二叉树的带权路径长度, 记为: WPL=Wk·Lk,其中Wk为第k个叶结点的权值,Lk 为第k个叶结点的 路径长度。如图(一)所示的二叉树,它的带权路径长度值WPL=2×2+ 4×2+5×2+3×2=28。
m1 = m2 = MaxValue; x1 = x2 = 0; for(j = 0; j < n+i;j++) { if(haffTree[j].weight < m1 && haffTree[j].flag == 0)
{ m2 = m1; x2 = x1; m1 = haffTree[j].weight; x1 = j;
0.03
0.03
10 110 11100 11101 11110 11111
图(三)构造哈夫曼树
表(三)指令的哈夫曼编码
对于该二叉树,我们可以规定向左的分支标记为1,向右的分支标记为
0。这样从根结点开始,沿线到达各频度指令对应的结点,所以经过的
分枝代码序列就构成了相应频度指令的哈夫曼编码,如表(三)所示。
D
0.15 0.05
E
0.04
F
0.03
为了充分利用编码信息和减少程序 的总位数,我们可以采用变长编码。 如果对每一条指令指定一条编码,使 得这些编码互不相同且最短,是否可 以满足要求呢?即是否可以如表(二) 所示这样编码呢?
表(二) 指令的变长编码
G
0.03
表(一)指令的使用频率
指令
编码
A
0
B
1
C
最优前缀码。
首先我们来看一个例子:
设有一台模型机,共有7种不同的 指令,其使用频率如表(一)所示。
指令
由于计算机内部只能识别0,1代码,
所以采用定长操作码,则需3位
A
使用频率(
wi)
0.40
(23=8)。显然,有一条编码没有作 B
0.30
用,这是一种浪费。一段程序中若有n C 条指令,那么程序的总位数为3×n。
//左孩子下标
int rightChild;
//右孩子下标
};
struct Code
//存放哈夫曼编码的数据
元素结构
{
int bit[MaxN];
//数组
int start;
//编码的起始下标
int weight;
//字符的权值
};
哈夫曼树构造算法如下:
void Haffman(int weight[], int n, HaffNode haffTree[])
(5) 哈夫曼编码的算法的实现 ①哈夫曼编码的数据结构设计 weight
flag
parent
leftChild
rightChild
为了在构造哈夫曼树时能方便的实现从双亲结点到左右孩子结点的操 作,在进行哈夫曼编码时能方便的实现从孩子结点到双亲结点的操作。 设计哈夫曼树的结点存储结构为双亲孩子存储结构。采用仿真指针实
else
haffTrerent = 0;
haffTree[i].flag = 0;
haffTree[i].leftChild = -1;
haffTree[i].rightChild = -1; } //构造哈夫曼树haffTree的n-1个非叶结点 for(i = 0;i < n-1;i++) {