第六章 树和二叉树(2)
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
结束
第 16 页
2)产生前缀码表 a) 找一个待编码的叶结点,没有此结点,算法结束。 b) 找该结点的双亲,如果无双亲,一个字符编码完成,转a)。 c) 有双亲,确定该结点是双亲的左(右)孩子,得到一位 编码值。 d) 以双亲为当前结点,转b) 对应字符的编码 见讲义算法6.12/6.13 a: 0110
哈夫曼树
哈夫曼树对应的静态三叉链表
结束
第 19 页
哈夫曼算法 void HuffmanTree(HuffmanTree &HT, int * w, int n){ //w 存放n 个字符的权值(均>0),构造赫夫曼树HT if (n<=1) return; m=2* n-1; HT=(HuffmanTree)malloc(m+1) * sizeof(HTNode); //为哈夫曼树分配存储 //空间 for (p=HT, i=1; i<=n; ++i, ++p, ++w) * p={ * w, 0, 0, 0}; //用给定的n个权// 值 ,构造n棵只有一个根结点的二叉树 for (; i<m; ++i; ++p) { //按构造哈夫曼树的步骤2、3、4,建哈夫曼树 //在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]存放新子树的根结点, HT[i].lchild=s1; HT[i].rchild=s2; HT[i].weight=HT[s1].weight+HT[s2].weight;
weight parent lchild rchild
HTNode类型的结构变量
结束
第 18 页
w 100 42 23 11 5 19 8 3 29 14 7 58 29 15 8 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
p 5 29 7 8 14 23 3 11 8 15 19 29 42 58 100
结束
第 2 页
60 30 15 30 15 60 30 15 5 10 30 15 5 15 10 15 30
结束
5 10
WPL=5*1+10*2+15*3+30*3=160
30 15
WPL=5*3+10*3+15*2+30*1=105
WPL=5*2+10*2+15*2+30*2=120
Βιβλιοθήκη Baidu
第 3 页
第 22 页
HT
w
p
lch rch
0 5 0 0 0 1 2 29 0 0 0 5 7 0 0 0 3 8 0 0 0 4 5 14 0 0 0 6 23 0 0 0 3 0 0 0 7 8 11 0 0 0 9 10 11 12 13 14 15 8 棵只有一个结点的二叉树
lch rch 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 1 12 3 13 8 14 5 15 6 15 2 0 13 0 0 0 0 0 0 0 0 7 4 9 10 11 12 14
w,p,lch,rch 是 weight,parent,l child,rchild 的缩写
100 60 30 15 5 10
结束
40 30
15
第 5 页
3 哈夫曼树的构造 构造哈夫曼树的步骤: 1.根据给定的n个权值 ,构造n棵只有一个根结点的二叉树, n个权值分 别是这些二叉树根结点的权。设F是由这n棵二叉树构成的集合 2.在F中选取两棵根结点权值最小的树作为左、右子树,构造一颗新的 二叉树,置新二叉树根的权值=左、右子树根结点权值之和; 3.从F中删除这两棵树,并将新树加入F; 4.重复 2、3,直到F中只含一棵树为止;
结束
第 20 页
例:用哈夫曼算法构造 以w=(5,29,7,8,14,23,3,11) 为权值的哈夫曼树
算 法 原 始 数 据
HT
w 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
p 5 29 7 8 14 23 3 11 8 15 19 29 42 58 100
lch rch 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 1 12 3 13 8 14 5 15 6 15 2 0 13 0 0 0 0 0 0 0 0 7 4 9 10 11 12 14
W
0 1 2 3 4 5 6 7 8
5 29 7 8 14 23 3 11
算 法 结 果 数 据
权值数组W
哈夫曼树对应的静态三叉链表HT
结束
第 21 页
哈夫曼算法主要步骤图示
HT
w 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
p
lch rch
为哈夫曼树分 配存储空间
结束
a: b: c: d: e: f: g: h: 0000 0001 0010 0011 010 011 10 11
结束
g e a b c d f
h
第 12 页
如何得到使二进制 串总长最短编码
应用中每个字符的使用频率是不一样的。显然,为使传输的二进制 串尽可能的短,使用频率高的字符用较短编码,使用频率低的字符用较 长的编码。如何使得电文最短呢?这就希望常用的字符编码尽可能的短。 统计语言各个字符的使用频度Wi,利用哈夫曼树就可以对这种语言 定义出一种最优的编码,使∑WiLi最小(电文最短)。
结束
第 6 页
例:构造以W=(5,15,40,30,10)为权的哈夫曼树。
100 5 15 40 30 10 30 15 5 10 15 40 30 5 15 10 15 60 30 40
60 30 15 5 10 15 40 30 5 15 10 30 15 40
结束
30
第 7 页
6.6.2 哈夫曼编码 1.哈夫曼编码 哈夫曼编码 哈夫曼树除了能求解最优判定问题解,还用于其他一些最优问题的求 解。这里介绍用哈夫曼树求解数据的二进制编码。 在进行数据通讯时,涉及数据编码问题。所谓数据编码就是数据与 二进制字符串的转换。例如:数据压缩、邮局发电报,发送方将原文转 换成二进制字符串,接收方将二进制字符串还原成原文。 原文 ---电文(二进制字符串) ----原文 例 要传输的原文为ABACCDA 设ABCD的编码为 A;00 B;01 C:10 D:11 发送方:将ABACCDA 转换成 00010010101100 接收方:将 00010010101100 还原为 ABACCDA
结束
第 9 页
采用不等长的编码,并且让字符串中出现频率大的字符的编码尽可 能的短,则电文的(字符串的编码)总长度即可减少,但这时会出现 编码的唯一性问题。 如果:A,B,C,D的编码分别为:0,00,1,01 则:上述电文:000011010 共9位,长度减少。但是译文困难。前面的 连续四个0,可以译成AAAA,BB,ABA。不唯一。 3).前缀 前缀编码 3).前缀编码 任一字符的编码都不是另一个字符编码的前缀。如果我们的不等长 编码是前缀编码,则问题就解决了。 前缀编码可以用二叉树来设计。方法: 1)字符放在叶结点上。 2)树中度为1的结点个数为0。 3)左右分支的编码分别为0,1。 4)从根结点到叶结点的路径上各分支的字符组成的二进制串作为 叶结点的编码。
b: c: d: e: f: g: h: 10 1110 1111 110 00 0111 010
结束
第 17 页
3.哈夫曼编码算法 设用一维数组W存储n个权值, 用静态三叉链表HT存储哈夫曼树
存储哈夫曼树的静态三叉链表类型定义 typedef struct { unsigned int weight; unsigned int parent, lchild, rchild; }HTNode, *HuffmanTree; //动态分配数组存储哈夫曼树
100 42 23 11 5 19 8 3 29 14 7 58 29 15 8 a: b: c: d: e: f: g: h: 0110 10 1110 1111 110 00 0111 010
结束
第 15 页
*哈夫曼树的应用 哈夫曼树的应用 1)报文到电文的译码 a) 从根出发 b) 取一位报文,若取完,译码结束。 c) 若报文=1,向右分支行进一个结点 若报文=0,向左分支行进一个结点 d) 若所得结点不是叶结点,转b) e) 若所得结点是叶结点,则字符即为译码结果,得到一个 字符,转a) 例:报文:111010001100100111 c b f e h g
结束
第 13 页
2.哈夫曼编码 目的:得到使报文最短的前缀码表 途径:构造哈夫曼树 依据:字符的使用频度
结束
第 14 页
设:有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),按哈夫曼算法构造 的一棵哈夫曼树如下: 对应字符的编码
分数 0-59 60-69 70-79 80-89 90-100 0.15 0.40 0.30 0.10 比例数 0.05
结束
第 4 页
按图的判定过程,转换一个分数所需的比较次数=从根到对应结点的路径 长度。转换10000个分数所需的总比较次数= 10000(0.05 × 1+0.15 × 2+0.4 × 3+0.3 × 4+0.1 × 4) 若将学生成绩在5个等级以上的分布比例看作描述判定过程二叉树叶子结 点权值,(0.05 × 1+0.15 × 2 +0.4 × 3+0.3 × 4+0.1 × 4)正是该二叉树的带 权路径长度。可见要想获得效率较高的转换程序,可构造以分数的分布 比例为权值的哈夫曼树。
2 应用举例 在求得某些判定问题时,利用哈夫曼树获得最佳判定算法。 例 编制一个将百分制转换成五分制的程序。 最直观的方法是利用if语句来的实现。可用二叉树描述判定过程。参 见课本P145 图6.23(a)。 如果这个程序很不经常使用,或要转换的分数不 多,不必考虑该程序效率,我们可以按照这个流程编程。 可是如果该程序经常要使用或数据量很大。比如对几十万学生的分 数进行转换,在这种情况下,要考虑转换程序的效率。 设有10000个百分制分数要转换,设学生成绩在5个等级以上的分布如 下:
结束
第 8 页
1).等长编码 1).等长编码 等长 每个字符都有相同长度的二进制编码。 我们上面的例子是一个等长编码的例子。 *优点:译文容易。 *缺点:报文长。 若某种文字有n个字符,每个字符的编码为k位,则: K=log2(n+1) 例如:英文字母26个,若要等长的给每个字母一个编码,则需要5 位二 进制。 2).不等长编码 2).不等长编码 不等长 每个字符具有长度不同的二进制编码。 在电报通讯的例子中,我们总希望电文长度尽可能的短。在数据 压缩时总希望压缩比尽可能的大。
结束
第 1 页
6.6 哈夫曼树及其应用
6.6.1 哈夫曼树及构造 1 哈夫曼树的概念 哈夫曼树的概念 路径:从一个祖先结点到子孙结点之间的分支构成这两个结点间的路径; 路径长度:路径上的分支数目称为路径长度; 结点的权:根据应用的需要可以给树的结点赋权值; 结点的带权路径长度:从根到该结点的路径长度与该结点权的乘积; 树的带权路径长度=树中所有叶子结点的带权路径之和; 通常记作 WPL= ∑ wi × Li 哈夫曼树:假设有n个权值(w1 , w2 , … , wn ),构造有n个叶子结点的二叉 树,每个叶子结点有一个 wi 作为它的权值。则带权路径长度最小的二叉 树称为哈夫曼树。 哈夫曼树。 哈夫曼树
结束
第 10 页
A :0
A B C
B: 10 C:11 用这种方式得到的编码是前缀编码。
结束
第 11 页
例 某通讯系统只使用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,利用二叉树设计一种不等长 编码: 1)构造以 a、b、c、d、e、f、g、h为叶子结点的二叉树; 2)将该二叉树所有左分枝标记0,所有右分枝标记1; 3)从根到叶子结点路径上标记作为叶子结点所对应字符的编码;