最优二叉树
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
频率
符
编码
频率
0.07
0.19
a
b
000
001
0.07
0.19
0 28
0 60 1
1 40 0 19 b
c
d
0.02
0.06
c
d
010
011
0.02
0.06
0001
01 00001 11
e
f g h
0.32
0.03 0.21 0.10
e
f g h
100
101 110 111
0.32
0.03 0.21 0.10
(1) 应用举例 在求得某些判定问题时,利用哈夫曼树获得最佳判定算法。 例:编制一个将百分制转换成五分制的程序。
设有10000个分数要转换,等级分布:
分数
比例数
0-59
0.05
60-69
0.15
70-79
0.40
80-89
0.30
90-100
0.10
构造以分数分布比例为权值 的树 a 60 按判定过程: 转换一个分数所需的比较次数= a 70 不及格 从根到对应结点的路径长度 a 80 及格 转换10000个分数所需的总比较次数= a 90 10000 中等 (0.05 1+0.15 2+0.4 3+0.3 4+0.1 4) 良好 优秀 二叉树的 带权路径长度
Huffman常译为赫夫曼、霍夫曼、哈夫曼等
树的带权路径长度如何计算?
经典之例:
WPL =
w kl k
k=1
n
树中所有叶子 结点的带权路 径长度之和 7 a
7
a
5
b
2 c
4 d
4 d
2 c 7 a
5 b (b)
5 b
2 c
4 d (c)
(a)
WPL= 36
WPL= 46
WPL= 35
Huffman树是WPL 最小的树
最佳判定方法
Y Y E Y D Y a<60 N a<70 N C Y B Y D 70a<80 N 80a<90 N 60a<70 N
a<80
N a<90 N A
Yபைடு நூலகம்
E
C
Y B
a<60
N A
(b)WPL=40x1+30x2+15x3+5x4+10x4=205
(a)WPL=10x4+30x4+40x3+15x2+5x1=315
0011
32 0 1 e 17 11 0 1 0 1 5 7 10 6 0 1 d a h 3 2 c f
1 21 g
Huffman码的WPL=2(0.19+0.32+0.21) + 4(0.07+0.06+0.10) +5(0.02+0.03)
=1.44+0.92+0.25=2.61 二进制等长码的WPL=3(0.19+0.32+0.21+0.07+0.06+0.10+0.02+0.03)=3
0
0 23 42 1 19 29 1
100
1
58
赫夫曼编码 1 2 3 4 5 6 7 8
0111 10 1110 1111 110 0 0 0110 0 10
0
0
1 29 1
0
11
3
0
8
1 5
14
7
15
0 1 8
哈夫曼编码算法
//-----哈夫曼树和哈夫曼编码的存储表示----typedef struct{ unsigned int weight; unsigned int parent, lchild, rchild; }HTNode, *HuffmanTree; //动态分配数组存储哈夫曼树 typedef char * *HuffmanCode; //动态分配数组存储哈夫曼编码表
void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n)
建哈夫曼树的算法如下:
{ //构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC. int m,i,s1,s2,start; unsigned c,f; HuffmanTree p; char *cd; if(n<=1) return; m=2*n-1; HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)) for(p=HT+1,i=1;i<=n;++i,++p,++w) //0号单未用 { (*p).weight=*w; (*p).parent=0; (*p).lchild=0; (*p).rchild=0; } for(;i<=m;++i,++p) (*p).parent=0; //1~n 赋权值 for(;i<=m;++i,++p) *p={0,0,0,0};//n+1~m 初始化
例2 设计哈夫曼编码,通信中可能有8种字符,其频率分别 为:0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11
HT的终态:
w={5, 29, 7, 8, 14, 23, 3, 11}
5 29 7
8 14 23 3 11
weight parent lchild rchild 1 5 0 0 0 2 29 0 0 0 3 7 0 0 0 4 8 0 0 0 5 14 0 0 0 6 23 0 0 0 7 3 0 0 0 8 11 0 0 0 9 0 0 0 0 0 0 10 0 0 0 11 0 0 0 12 0 0 0 13 0 0 0 14 0 0 0 15
哈夫曼编码的另一种表示: 1.00
0 0.40 0 g 0.21 1
1
b 0.19
0
0.28 0 0.17 1
0.60 1 e 0.32
0.11 0 1
0
1 d 0.07 0.06
h 0.10
哈夫曼编码树
a
0.05
0 f 0.03 1 c 0.02
练习题:设计哈夫曼编码,通信中可能有8种字符,其频率 分别为:0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11
0 d
1
0
i 0 a
1
1 n
Huffman编码结果:d=0, i=10, a=110, n=111 WPL=1bit×7+2bit×5+3bit(2+4)=35(小于等长码的WPL=36) 特征:每一码不会是另一码的前缀,译码时唯一,不会错! Huffman编码也称为前缀码
Huffman编码
哈夫曼编码的基本思想是——— 出现概率大的信息用短码,概率小的用长码
续:
for(i=n+1;i<=m;++i){ //建哈夫曼树 //在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;
// 从叶子到根逆向求每个字符的赫夫曼编码----HC=(HffmanCode)malloc((n+1*sizeof(char *)); //分配n个字符编码的头指针向量 cd=(char *)malloc(n*sizeof(char)); //分配求编码的工作空间 cd[n-1]=“\0"; //编码结束符. for(i=1;i<=n;++i) { //逐个字符求赫夫曼编码 start=n-1; //编码结束符位置 for( c=i, f=HT[i]. parent ; f!=0; c=f, f=Ht[f].parent ) //从叶子至根逆向求编码 if(HT[f].lchild= =c) cd[--start]= "0"; else cd[--start]= "1"; Hc[i]=(char *)malloc((n-start)*sizeof(char)); //为第i个字符编码分配空间 strcpy(HC[i], &cd[start]); //从cd复制编码(串)到HC } free(cd); //释放工作空间 }//HuffanCoding
7.5
Huffman树及其应用
1、Huffman树的定义
2、Huffman编码
带权路径长 度最短的树
Huffman树 最优二叉树
Huffman编码
不等长编码
是通信中最 经典的压缩 编码
最优二叉树(Huffman树)
(1)若干术语: 路
d 径: 由一结点到另一结点间的分支所构成。 b e
a c f g
wi 的根结点,其左右子树均空。
(2) 在F 中选取两棵根结点权值最小的树 做为左右子树构造一棵新 的二叉树,且让新二叉树根结点的权值等于其左右子树的根结
点权值之和。
(3) 在F 中删去这两棵树,同时将新得到的二叉树加入 F中。 (4) 重复(2) 和(3) , 直到 F 只含一棵树。这棵树便是Huffman树。
讨论1. 构造Huffman树的基本思想:
WPL最小的树
权值大的结点用短路径,权值小的结点用长路径。 讨论:Huffman树有什么用? 信息高效传输 例:设有4个字符d,i,a,n,出现的频度分别为7,5,2,4, 怎样编码才能使它们组成的报文在网络中传得最快? 法1:等长编码(如二进制编码)
令d=00,i=01,a=10,n=11,则: WPL1=2×(7+5+2+4)=36
}
2、求哈夫曼编码的算法 思想方法 以叶子T[i](1≤i≤n)为出发点,向上回溯至根为止。走 左分支则0,右分支1。
注意: ① 由于生成的编码与要求的编码反序,将生成的代码先 从后往前依次存放在一个临时向量中,并设一个指针start指 示编码在该向量中的起始位置。 ② 当某字符编码完成时,从临时向量的start处将编 码复制到该字符相应的位串HC中即可。 ③ 因为字符集大小为n,故变长编码的长度不会超过n, 加上一个结束符'\0',HC的大小应为n+1。
void Select (HuffmanTree HT,int t,int&s1,int&s2) {//在HT[1...t]中选择parent为0且权值最小的两个结点,其 序号分别为s1和s2 int i, m, n; m=n=100000; for(i=1;i<=t;i++) {if(HT[i].parent==0&&(HT[i].weight<m||HT[i].weight<n)) if(m<n) { n=HT[i].weight ; s2=i ; } else { m=HT[i].weight ; s1=i ; } } if(s1>s2) //s1放较小的序号 {i=s1;s1=s2;s2=i;} }
路径长度: 路径上的分支数目。 a→e的路径长度= 2
树长度=10 树的路径长度: 从树根到每一结点的路径长度之和。
带权路径长度: 结点到根的路径长度与结点上权的乘积(WPL)
Weighted Path Length
树的带权路径长度: 树中所有叶子结点的带权路径长度之和
Huffman树:
带权路径长度最小的树。
法2:不等长编码(如Huffman编码)
频度高的信息 用短码,反之 用长码,传输 效率肯定高!
令d=0;i=10,a=110,n=111,则: WPL2=1×7+2×5+3×(2+4)=35 明确:要实现Huffman编码,就要先构造Huffman树
讨论2. 构造Huffman树的步骤(即Huffman算法): (1) 由给定的 n 个权值{ w1, w2, …, wn }构成n棵二叉树的集合F = { T1, T2, …, Tn } (即森林) ,其中每棵二叉树 Ti 中只有一个带权为
例1:假设用于通信的电文仅由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 }, 按哈夫曼树构造规则(合并、删除、替换),可得到哈夫曼树。
具体构造过程: w={ 7, 2, √ 6, 32, √ 3, 21, 10 √ 19, √ √ } 60
请注意:哈 夫曼树样式 不唯一! 5 2 c 3 f 28 11 6 d 7 a
100
32 e 17 10 h
40 19 b 21 g
对应的哈夫曼编码:
符
100
a
b
编码 0010 10 00000
具体操作步骤: step1:对权值进行合并、删除与替换 ——在权值集合{7,5,2,4}中,总是合并当前值最小的两个权 a. 初始 c. 合并{5} {6} d. 合并{7} {11}
b. 合并{2} {4}
方框表示叶子, 字符
圆框表示合并后 的权值
step2:按左“0”右“1” 对Huffman树的所有分支编号 ——将 Huffman树 与 Huffman编码 挂钩