最优二叉树哈夫曼树Word文件下载.docx
- 文档编号:16988642
- 上传时间:2022-11-27
- 格式:DOCX
- 页数:21
- 大小:47.79KB
最优二叉树哈夫曼树Word文件下载.docx
《最优二叉树哈夫曼树Word文件下载.docx》由会员分享,可在线阅读,更多相关《最优二叉树哈夫曼树Word文件下载.docx(21页珍藏版)》请在冰豆网上搜索。
4000
14.00
6.50
3.70
=6000>
5000
16.00
7.50
4.30
>
6000
20.00
表7.1国家邮政局制定的快递包裹参考标准
根据表7.1可以制定出许多种二叉树,但不同的二叉树判定的次数可能不一样,执行的效率也不同。
例7.2铁球分类
现有一批球磨机上的铁球,需要将它分成四类:
直径不大于20的属于第一类;
直径大于20而不大于50的属于第二类;
直径大于50而不大于100的属于第三类;
其余的属于第四类;
假定这批球中属于第一、二、三、四类铁球的个数之比例是1:
2:
3:
4。
我们可以把这个判断过程表示为图7.1中的两种方法:
图7.1两种判断二叉树示意图
那么究竟将这个判断过程表示成哪一个判断框,才能使其执行时间最短呢?
让我们对上述判断框做一具体的分析。
假设有1000个铁球,则各类铁球的个数分别为:
100、200、300、400;
对于图7.1中的左图和右图比较的次数分别如表7.2所示:
左图
右图
序号
比较式
比较次数
1
a<
=20
a>
100
2
=50
900
50
600
3
=100
700
300
合计
2600
1900
表7.2两种判断二叉树比较次数
过上述分析可知,图7.1中右图所示的判断框的比较次数远远小于左图所示的判断框的比较次数。
为了找出比较次数最少的判断框,将涉及到树的路径长度问题。
7.1哈夫曼树的基本概念
最优二叉树,也称哈夫曼(Haffman)树,是指对于一组带有确定权值的叶结点,构造的具有最小带权路径长度的二叉树。
那么什么是二叉树的带权路径长度呢?
在前面我们介绍过路径和结点的路径长度的概念,而二叉树的路径长度则是指由根结点到所有叶结点的路径长度之和。
如果二叉树中的叶结点都具有一定的权值,则可将这一概念加以推广。
设二叉树具有n个带权值的叶结点,那么从根结点到各个叶结点的路径长度与相应结点权值的乘积之和叫做二叉树的带权路径长度,记为:
n
∑
k=1
WPL=Wk·
Lk
其中Wk为第k个叶结点的权值,Lk为第k个叶结点的路径长度。
如图7.2所示的二叉树,它的带权路径长度值WPL=2×
2+4×
2+5×
2+3×
2=28。
在给定一组具有确定权值的叶结点,可以构造出不同的带权二叉树。
例如,给出4个叶结点,设其权值分别为1,3,5,7,我们可以构造出形状不同的多个二叉树。
这些形状不同的二叉树的带权路径长度将各不相同。
图7.3给出了其中5个不同形状的二叉树。
这五棵树的带权路径长度分别为:
(a)WPL=1×
2+7×
2=32
5
4
(b)WPL=1×
3+3×
3+5×
1=29
(c)WPL=1×
3+7×
1=33
(d)WPL=7×
2+1×
1=43图7.2一个带权二叉树
(e)WPL=7×
1+5×
3+1×
3=29
7
(a)(b)(c)
(d)(e)
图7.3具有相同叶子结点和不同带权路径长度的二叉树
由此可见,由相同权值的一组叶子结点所构成的二叉树有不同的形态和不同的带权路径长度,那么如何找到带权路径长度最小的二叉树(即哈夫曼树)呢?
根据哈夫曼树的定义,一棵二叉树要使其WPL值最小,必须使权值越大的叶结点越靠近根结点,而权值越小的叶结点越远离根结点。
哈夫曼(Haffman)依据这一特点于1952年提出了一种方法,这种方法的基本思想是:
(1)由给定的n个权值{W1,W2,…,Wn}构造n棵只有一个叶结点的二叉树,从而得到一个二叉树的集合F={T1,T2,…,Tn};
(2)在F中选取根结点的权值最小和次小的两棵二叉树作为左、右子树构造一棵新的二叉树,这棵新的二叉树根结点的权值为其左、右子树根结点权值之和;
(3)在集合F中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入到集合F中;
(4)重复
(2)(3)两步,当F中只剩下一棵二叉树时,这棵二叉树便是所要建立的哈夫曼树。
由于这种算法是哈夫曼最早提出的,所以将最优二叉树称为哈夫曼树。
图7.4给出了前面提到的叶结点权值集合为W={1,3,5,7}的哈夫曼树的构造过程。
可以计算出其带权路径长度为29,由此可见,对于同一组给定叶结点所构造的哈夫曼树,树的形状可能不同,但带权路径长度值是相同的,一定是最小的。
第一步第二步
第三步第四步
16
9
图7.4哈夫曼树的建立过程
7.2哈夫曼树的构造算法
从上述算法中可以看出,F实际上是森林,该算法的思想是不断地进行森林F中的二叉树的“合并”,最终得到哈夫曼树。
算法一:
在构造哈夫曼树时,可以设置一个结构数组HuffNode保存哈夫曼树中各结点的信息,根据二叉树的性质可知,具有n个叶子结点的哈夫曼树共有2n-1个结点,所以数组HuffNode的大小设置为2n-1,数组元素的结构形式如下:
rchild
weight
lchild
parent
其中,weight域保存结点的权值,lchild和rchild域分别保存该结点的左、右孩子结点在数组HuffNode中的序号,从而建立起结点之间的关系。
为了判定一个结点是否已加入到要建立的哈夫曼树中,可通过parent域的值来确定。
初始时parent的值为-1,当结点加入到树中时,该结点parent的值为其双亲结点在数组HuffNode中的序号,就不会是-1了。
构造哈夫曼树时,首先将由n个字符形成的n个叶结点存放到数组HuffNode的前n个分量中,然后根据前面介绍的哈夫曼方法的基本思想,不断将两个小子树合并为一个较大的子树,每次构成的新子树的根结点顺序放到HuffNode数组中的前n个分量的后面。
下面给出哈夫曼树的构造算法。
constmaxvalue=10000;
{定义最大权值}
maxleat=30;
{定义哈夫曼树中叶子结点个数}
maxnode=maxleaf*2-1;
typeHnodeType=record
weight:
integer;
parent:
lchild:
rchild:
end;
HuffArr:
array[0..maxnode]ofHnodeType;
var……
procedureCreatHaffmanTree(varHuffNode:
HuffArr);
{哈夫曼树的构造算法}
vari,j,m1,m2,x1,x2,n:
begin
readln(n);
{输入叶子结点个数}
fori:
=0to2*n-1do{数组HuffNode[]初始化}
begin
HuffNode[i].weight=0;
HuffNode[i].parent=-1;
HuffNode[i].lchild=-1;
HuffNode[i].rchild=-1;
=0ton-1doread(HuffNode[i].weight);
{输入n个叶子结点的权值}
=0ton-1do{构造哈夫曼树}
begin
m1:
=MAXVALUE;
m2:
x1:
=0;
x2:
forj:
=0ton+i-1do
if(HuffNode[j].weight<
m1)and(HuffNode[j].parent=-1)then
beginm2:
=m1;
=x1;
m1:
=HuffNode[j].weight;
=j;
end
elseif(HuffNode[j].weight<
m2)and(HuffNode[j].parent=-1)then
{将找出的两棵子树合并为一棵子树}
HuffNode[x1].parent:
=n+i;
HuffNode[x2].parent:
HuffNode[n+i].weight:
=HuffNode[x1].weight+HuffNode[x2].weight;
HuffNode[n+i].lchild:
HuffNode[n+i].rchild:
=x2;
算法二:
实际上,哈夫曼算法的实现与实际问题所采用的存储结构有关。
现假设用数组F来存储哈夫曼树,其中第i个数组元素F[i]是哈夫曼树中的一个结点,其地址为i,有3个域,Data域存放该结点的权值,lChild域和rChild域分别存放该结点左、右子树的根结点的地址(下标)。
在初始状态下:
F[i].Data=Wi,F[i].lChild=F[i].rChild=0,i=1,2,…,n。
即先构造了n个叶子。
在以后每步构造一棵新二叉树时,都需要对森林中所有二叉树的根结点进行排序,因此可用数组a作为排序暂存空间,其中第i个数组元素a[i]是森林F中第i棵二叉树的根结点,有2个域,Data是根结点所对应的权值,Addr是根结点在F中的地址(下标)。
a[i].Data=Wi,a[i].Addr=i,i=1,2,…n。
PROCEDURECreateHuffmanTree(F,t,a,n)
{已知n个权值a[i],构造哈夫曼树F,且根结点地址(下标)为t}
VARi:
Integer;
BEGIN
FORi:
=1TOnDOBEGIN{初始化}
F[i].Data:
=a[i].Data;
F[i].lChild:
F[i].rChild:
a[i].Addr:
=i
END;
t:
=n+1;
{t指向下一个可利用单元}
i:
=n;
{当前森林中的二叉树是i}
WHILEi>
=2DOBEGIN
Insert(a,i);
{对a的前i个元素按Data域进行排序}
F[t].Data:
=a[1].Data+a[2].Data;
{生成新的二叉树}
F[t].lChild:
=a[1].Addr;
F[t].rChild:
=a[2].Addr;
a[1].Data:
=F[t].Data;
{修改森林}
a[1].Addr:
=t;
a[2].Data:
a[2].Addr:
=a[i].Addr;
i:
=i-1;
{二叉树数目减一}
t:
=t+1;
7.3哈夫曼树在编码问题中的应用
在数据通讯中,经常需要将传送的文字转换成由二进制字符0,1组成的二进制串,我们称之为编码。
例如,假设要传送的电文为ABACCDA,电文中只含有A,B,C,D四种字符,若这四种字符采用表7.3(a)所示的编码,则电文的代码为000010000100100111000,长度为21。
在传送电文时,我们总是希望传送时间尽可能短,这就要求电文代码尽可能短,显然,这种编码方案产生的电文代码不够短。
表7.3(b)所示为另一种编码方案,用此编码对上述电文进行编码所建立的代码为00010010101100,长度为14。
在这种编码方案中,四种字符的编码均为两位,是一种等长编码。
如果在编码时考虑字符出现的频率,让出现频率高的字符采用尽可能短的编码,出现频率低的字符采用稍长的编码,构造一种不等长编码,则电文的代码就可能更短。
如当字符A,B,C,D采用表7.3(c)所示的编码时,上述电文的代码为0110010101110,长度仅为13。
表a表b表c表d
字符编码字符编码字符编码字符编码
A000A00A0A01
B010B01B110B010
C100C10C10C001
D111D11D111D10
表7.3字符的四种不同的编码方案
哈夫曼树可用于构造使电文的编码总长最短的编码方案。
具体做法如下:
设需要编码的字符集合为{d1,d2,…,dn},它们在电文中出现的次数或频率集合为{w1,w2,…,wn},以d1,d2,…,dn作为叶结点,w1,w2,…,wn作为它们的权值,构造一棵哈夫曼树,规定哈夫曼树中的左分支代表0,右分支代表1,则从根结点到每个叶结点所经过的路径分支组成的0和1的序列便为该结点对应字符的编码,我们称之为哈夫曼编码。
在哈夫曼编码树中,树的带权路径长度的含义是各个字符的码长与其出现次数的乘积之和,也就是电文的代码总长,所以采用哈夫曼树构造的编码是一种能使电文代码总长最短的不等长编码。
在建立不等长编码时,必须使任何一个字符的编码都不是另一个字符编码的前缀,这样才能保证译码的唯一性。
例如表7.3(d)的编码方案,字符A的编码01是字符B的编码010的前缀部分,这样对于代码串0101001,既是AAC的代码,也是ABD和BDA的代码,因此,这样的编码不能保证译码的唯一性,我们称之为具有二义性的译码。
然而,采用哈夫曼树进行编码,则不会产生上述二义性问题。
因为,在哈夫曼树中,每个字符结点都是叶结点,它们不可能在根结点到其它字符结点的路径上,所以一个字符的哈夫曼编码不可能是另一个字符的哈夫曼编码的前缀,从而保证了译码的非二义性。
为了不等长编码不是前缀编码,可用该字符集中的每个字符作为叶子结点生成一棵编码二叉树,为了获得传送电文的最短长度,可将每个字符出现频率作为字符结点的权值赋予给结点上,求出此树的最小带权路径长度就等于求出了传送电文的最短长度。
因此,求传送电文的最短长度问题就转化为求由字符集中的所有字符作为叶子结点,由字符的出现频率作为其权值所产生的哈夫曼树的问题。
例如,假定电文中只使用A、B、C、D、E、F这六种字符,若进行等长编码,它们分别需要3位二进制字符,可依次编码为000、001、010、011、100、101。
由常识可知,电文中的每个字符的出现频率一般是不同的。
假定在一份电文中,这6个字符的出现频率分别为4、2、6、8、3、2,则电文被编码后的总长度L为:
L=3×
(4+2+6+8+3+2)=75
图6编码哈夫曼树
根据前面所讨论的例子,生成的编码哈夫曼树如图6所示。
由编码哈夫曼树得到的字符编码称作哈夫曼编码。
在图6中,A、B、C、D、E、F这6个字符的哈夫曼编码分别是:
00、1110、01、10、110、1111。
电文的最短传送长度为:
L=WPL=4×
2+2×
4+6×
2+8×
2+3×
3+2×
4=61
显然,这要比等长编码所得到的传送总长度75要小的多。
下面讨论实现哈夫曼编码的算法。
实现哈夫曼编码的算法可分为两大部分:
(1)构造哈夫曼树;
(2)在哈夫曼树上求叶结点的编码。
求哈夫曼编码,实质上就是在已建立的哈夫曼树中,从叶结点开始,沿结点的双亲链域回退到根结点,每回退一步,就走过了哈夫曼树的一个分支,从而得到一位哈夫曼码值,由于一个字符的哈夫曼编码是从根结点到相应叶结点所经过的路径上各分支所组成的0,1序列,因此先得到的分支代码为所求编码的低位码,后得到的分支代码为所求编码的高位码。
我们可以设置一结构数组HuffCode用来存放各字符的哈夫曼编码信息,数组元素的结构如下:
start
bit
其中,分量bit为一维数组,用来保存字符的哈夫曼编码,start表示该编码在数组bit中的开始位置。
所以,对于第i个字符,它的哈夫曼编码存放在HuffCode[i].bit中的从HuffCode[i].start到n的分量上。
数据结构如下:
typecodetype=record
bit:
array[1..n]ofinteger;
sp:
1..n;
ch:
char;
codes=array[1..n]ofcodetype;
其中,bit表示n位二进制代码,sp表示代码的起始位置,ch代表字符本身。
如下表哈夫曼编码数据结构为:
Bit[1]
…
Bit[n]
sp
ch
A
B
C
D
【求哈夫曼编码程序段】
constMaxleaf=128;
{定义最多叶结点数}
MaxNode=255;
{定义最大结点数}
MaxBit=10;
{定义哈夫曼编码的最大长度}
typeHCodeType=record
array[0..MaxBit]ofinteger;
start:
……
procedureHaffmanCode;
{生成哈夫曼编码}
varHuffNode:
array[0..MaxNode]ofHCodeType;
HuffCode:
array[0..MaxLeaf]ofHcodeType;
cd:
HcodeType;
i,j,c,p:
integer;
HuffmanTree(HuffNode);
{建立哈夫曼树}
fori:
=0ton-1do{求每个叶子结点的哈夫曼编码}
cd.start:
=n-1;
c:
=i;
p:
=HuffNode[c].parent;
whilep<
0do{由叶结点向上直到树根}
ifHuffNode[p].lchild=cthencd.bit[cd.start]:
=0
elsecd.bit[cd.start]:
=1;
dec(cd.start);
=p;
=cd.start+1ton-1do{保存求出的每个叶结点的哈夫曼编码和编码的起始位}
begin
HuffCode[i].bit[j]:
=cd.bit[j];
HuffCode[i].start=cd.start;
end;
=0ton-1do{输出每个叶子结点的哈夫曼编码}
forj:
=HuffCode[i].start+1ton-1dowrite(HuffCode[i].bit[j]:
10);
writeln;
例题1:
根据传送的字母出现的频率,假设共有n个字符要求编码,设置相应的哈夫曼编码。
算法步骤:
1.输入字符串,统计各个字符出现的次数;
2.建立哈夫曼树;
3.从哈夫曼树产生哈夫曼编码;
4.打印输出各个字母的哈夫曼编码。
程序:
PROGRAMhtreecode(input,output);
Constn=4;
M=2*n-1;
Max=10000;
Typenode=record
Cord:
W:
integer;
Parent,lchild,rchild:
0..m;
End;
Htree=array[1..m]ofnode;
varI,j,i1,p1,p2,small1,small2:
cd:
codetype;
ht:
htree;
cha:
array[’A’..’Z’]ofinteger;
ch1:
bm:
codes;
procedurecreatehtree(varht:
htree);
{建立哈夫曼树}
=1tomdo
ht[i].lchild:
ht[i].rchild:
ht[i].parent:
=n+1tomdo
p1:
p2:
small1:
=max;
small2:
=1toi-1do
ifht[j].parent=0then
ifht[j].w,small1then
small2:
=small1;
=ht[j].w;
=p1;
p1:
elseifht[j].w<
=small2then
ht[p1].parent:
=I;
ht[p2].parent:
ht[i].lchild:
=p2;
ht[i].w:
=ht[p1].w+ht[p2].w;
procedurehcode(varbm:
codes,ht:
{从哈夫曼树产生哈夫曼编码}
=1tondo
=1tondobm[i].bit[j]:
=1tondo
cd.sp:
=1tondocd.bit[j]:
i1:
=ht[i].parent;
0do
ifht[p].lchild=i1thencd.bit[cd.sp]:
=0elsecd.bit[cd.sp]:
=cd.sp-1;
i1:
p:
=ht[
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 最优 二叉 树哈夫曼树