数据结构哈夫曼树的构造及其应用课程设计实验报告Word格式文档下载.docx

上传人:b****6 文档编号:20405010 上传时间:2023-01-22 格式:DOCX 页数:12 大小:61.67KB
下载 相关 举报
数据结构哈夫曼树的构造及其应用课程设计实验报告Word格式文档下载.docx_第1页
第1页 / 共12页
数据结构哈夫曼树的构造及其应用课程设计实验报告Word格式文档下载.docx_第2页
第2页 / 共12页
数据结构哈夫曼树的构造及其应用课程设计实验报告Word格式文档下载.docx_第3页
第3页 / 共12页
数据结构哈夫曼树的构造及其应用课程设计实验报告Word格式文档下载.docx_第4页
第4页 / 共12页
数据结构哈夫曼树的构造及其应用课程设计实验报告Word格式文档下载.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

数据结构哈夫曼树的构造及其应用课程设计实验报告Word格式文档下载.docx

《数据结构哈夫曼树的构造及其应用课程设计实验报告Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《数据结构哈夫曼树的构造及其应用课程设计实验报告Word格式文档下载.docx(12页珍藏版)》请在冰豆网上搜索。

数据结构哈夫曼树的构造及其应用课程设计实验报告Word格式文档下载.docx

2.1哈夫曼树的构造2

第三章哈夫曼树的存储结构及哈夫曼算法的实现3

3.1哈夫曼树的存储结构3

3.2哈夫曼算法的简要描述3

第四章哈夫曼树的应用5

4.1哈夫曼编码5

4.2求哈夫曼编码的算法5

4.21思想方法5

4.22字符集编码的存储结构及其算法描述6

4.3哈夫曼树和编码程序实现:

6

4.4程序运行结果:

9

心得体会10

参考文献10

    第一章哈夫曼树的基本术语

1.1路径和路径长度

在一棵树中,从一个结点往下可以达到的孩子或子孙结点之间的通路,称为路径。

通路中分支的数目称为路径长度。

若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。

1.2结点的权及带权路径长度

若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。

结点的带权路径长度为:

从根结点到该结点之间的路径长度与该结点的权的乘积。

1.2树的带权路径长度

树的带权路径长度(WeightedPathLengthofTree):

也称为树的代价,定义为树中所有叶结点的带权路径长度之和,通常记为:

其中:

n表示叶子结点的数目

wi和li分别表示叶结点ki的权值和根到结点ki之间的路径长度。

1.3哈夫曼树的定义

在权为wl,w2,…,wn的n个叶子所构成的所有二叉树中,带权路径长度最小(即代价最小)的二叉树称为最优二叉树或哈夫曼树。

[例]给定4个叶子结点a,b,c和d,分别带权7,5,2和4。

构造如下图所示的三棵二叉树(还有许多棵),它们的带权路径长度分别为:

(a)WPL=7*2+5*2+2*2+4*2=36

(b)WPL=7*3+5*3+2*1+4*2=4

(c)WPL=7*1+5*2+2*3+4*3=35

其中(c)树的WPL最小,可以验证,它就是哈夫曼树。

第二章哈夫曼树的构造

2.1哈夫曼树的构造

(a)初始森林

7524

(b)c与d合并

18

711

711

566

5

2

244

图1哈夫曼树的构造过程

假设有n个权值,则构造出的哈夫曼树有n个叶子结点。

n个权值分别设为w1,w2,…,wn,则哈夫曼树的构造规则为:

(1)将w1,w2,…,wn看成是有n棵树的森林(每棵树仅有一个结点);

(2)在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;

(3)从森林中删除选取的两棵树,并将新树加入森林;

(4)重复

(2)、(3)步,直到森林中只剩一棵树为止,该树即为我们所求得的哈夫曼树。

下面给出哈夫曼树的构造过程,假设给定的叶子结点的权分别为1,5,7,3,则构造哈夫曼树过程如下图所示。

从图中可知,n个权值构造哈夫曼树需n-1次合并,每次合并,森林中的树数目减1,最后森林中只剩下一棵树,即为我们求得的哈夫曼树。

第三章哈夫曼树的存储结构及哈夫曼算法的实现

3.1哈夫曼树的存储结构

用一个大小为2n-1的向量来存储哈夫曼树中的结点,其存储结构为:

#definen100//叶子数目

#definem2*n-1//树中结点总数

typedefstruct

{//结点类型

floatweight;

//权值,不妨设权值均大于零

intlchild,rchild,parent;

//左右孩子及双亲指针

}HTNode;

typedefHTNodeHuffmanTree[m];

//HuffmanTree是向量类型

因为C语言数组的下界为0,故用-1表示空指针。

树中某结点的lchild、rchild和parent不等于-1时,它们分别是该结点的左、右孩子和双亲结点在向量中的下标。

这里设置parent域有两个作用:

其一是使查找某结点的双亲变得简单;

其二是可通过判定parent的值是否为-1来区分根与非根结点。

3.2哈夫曼算法的简要描述

在上述存储结构上实现的哈夫曼算法可大致描述为(设T的类型为HuffmanTree):

(1)初始化

将T[0..m-1]中2n-1个结点里的三个指针均置为空(即置为-1),权值置为0。

(2)输人

读人n个叶子的权值存于向量的前n个分量(即T[0..n-1])中。

它们是初始森林中n个孤立的根结点上的权值。

(3)合并

对森林中的树共进行n-1次合并,所产生的新结点依次放人向量T的第i个分量中(n≤i≤m-1)。

每次合并分两步:

①在当前森林T[0..i-1]的所有结点中,选取权最小和次小的两个根结点[p1]和T[p2]作为合并对象,这里0≤p1,p2≤i-1。

②将根为T[p1]和T[p2]的两棵树作为左右子树合并为一棵新的树,新树的根是新结点T[i]。

具体操作:

将T[p1]和T[p2]的parent置为i,

将T[i]的lchild和rchild分别置为p1和p2

新结点T[i]的权值置为T[p1]和T[p2]的权值之和。

注意:

合并后T[pl]和T[p2]在当前森林中已不再是根,因为它们的双亲指针均已指向了T[i],所以下一次合并时不会被选中为合并对象。

第四章哈夫曼树的应用

4.1哈夫曼编码

通信中,可以采用0,1的不同排列来表示不同的字符,称为二进制编码。

而哈夫曼树在数据编码中的应用,是数据的最小冗余编码问题,它是数据压缩学的基础。

若每个字符出现的频率相同,则可以采用等长的二进制编码,若频率不同,则可以采用不等长的二进编码,频率较大的采用位数较少的编码,频率较小的字符采用位数较多的编码,这样可以使字符的整体编码长度最小,这就是最小编码

的问题。

而哈夫曼编码就是一种不等长的二进制编码,且哈夫曼树是一种最优二叉树,它的编码也是一种最优编码,在哈夫曼树中,规定往左编码为0,往右编码为1,则得到叶子结点编码为从根结点到叶子结点中所有路径中0和1的顺序排列。

例如,给定权{1,5,7,3},得到的哈夫曼树及编码见图6-32(假定权值就代表该字符名字)。

1的哈夫曼编码100

5的哈夫曼编码11

7的哈夫曼编码0

3的哈夫曼编码101

图6-31构造哈夫曼编码树

4.2求哈夫曼编码的算法

4.21思想方法

给定字符集的哈夫曼树生成后,求哈夫曼编码的具体实现过程是:

依次以叶子T[i](0≤i≤n-1)为出发点,向上回溯至根为止。

上溯时走左分支则生成代码0,走右分支则生成代码1。

①由于生成的编码与要求的编码反序,将生成的代码先从后往前依次存放在一个临时向量中,并设一个指针start指示编码在该向量中的起始位置(start初始时指示向量的结束位置)。

②当某字符编码完成时,从start处将编码复制到该字符相应的位串cd中即可。

4.22字符集编码的存储结构及其算法描述

typedefstruct

{

charcd[N];

/*存放哈夫曼码*/

intstart;

}HCode;

//hfmTree.cpp:

Definestheentrypointfortheconsoleapplication.

//

#include"

stdio.h"

#include<

stdio.h>

string.h>

#defineN4/*叶子结点数*/

#defineM2*N-1/*树中结点总数*/

chardata;

/*结点值*/

intweight;

/*权重*/

intparent;

/*双亲结点*/

intlchild;

/*左孩子结点*/

intrchild;

/*右孩子结点*/

}HTNode;

voidCreateHT(HTNodeht[],intn)

inti,k,lnode,rnode;

intmin1,min2;

for(i=0;

i<

2*n-1;

i++)/*所有结点的相关域置初值-1*/

{

ht[i].parent=ht[i].lchild=ht[i].rchild=-1;

}

//n——2*n-1节点的数据域置为*,权值为-1,主要是为显示用,不影响生成哈夫曼树和编码

for(i=n;

i++)

ht[i].data='

*'

;

ht[i].weight=-1;

printf("

构建哈夫曼树,存储结构的初始情况:

\n"

);

data\tweight\tparent\tlchild\trchild\n"

for(i=0;

i++)

%c\t%d\t%d\t%d\t%d\n"

ht[i].data,ht[i].weight,ht[i].parent,ht[i].lchild,ht[i].rchild);

//显示结束

i++)/*构造哈夫曼树*/

min1=min2=32767;

/*lnode和rnode为最小权重的两个结点位置*/

lnode=rnode=-1;

for(k=0;

k<

=i-1;

k++)

if(ht[k].parent==-1)/*只在尚未构造二叉树的结点中查找*/

if(ht[k].weight<

min1)

min2=min1;

rnode=lnode;

min1=ht[k].weight;

lnode=k;

elseif(ht[k].weight<

min2)

min2=ht[k].weight;

rnode=k;

ht[lnode].parent=i;

ht[rnode].parent=i;

ht[i].weight=ht[lnode].weight+ht[rnode].weight;

ht[i].lchild=lnode;

ht[i].rchild=rnode;

}

voidCreateHCode(HTNodeht[],HCodehcd[],intn)

inti,f,c;

HCodehc;

n;

i++)/*根据哈夫曼树求哈夫曼编码*/

hc.start=n-1;

c=i;

f=ht[i].parent;

while(f!

=-1)/*循序直到树根结点*/

if(ht[f].lchild==c)/*处理左孩子结点*/

hc.cd[hc.start--]='

0'

else/*处理右孩子结点*/

1'

c=f;

f=ht[f].parent;

hc.start++;

/*start指向哈夫曼编码最开始字符*/

hcd[i]=hc;

voidDispHCode(HTNodeht[],HCodehcd[],intn)

inti,k;

intsum=0,m=0,j;

输出哈夫曼编码:

/*输出哈夫曼编码*/

j=0;

%c:

\t"

ht[i].data);

for(k=hcd[i].start;

%c"

hcd[i].cd[k]);

j++;

m+=ht[i].weight;

sum+=ht[i].weight*j;

\n平均长度=%g\n"

1.0*sum/m);

intmain()

intn=4,i;

charstr[]={'

a'

'

b'

c'

d'

};

intfnum[]={5,3,1,7};

HTNodeht[M];

HCodehcd[N];

ht[i].data=str[i];

ht[i].weight=fnum[i];

CreateHT(ht,n);

printf("

CreateHCode(ht,hcd,n);

DispHCode(ht,hcd,n);

return0;

心得体会:

通过这次的课程设计,让我对数据结构有了一个比较深刻的了解。

课程设计非常锻炼人,每完成一个项目,不仅是知识体系的完善和知识的验证,更是编程技术的提升,当自己编的多了,就会开始摸索编程的捷径,想着用更高效的方法去完成一个个项目,就这样在一次次的锻炼中自己会慢慢的提高。

参考文献

[1]唐策善,李龙澍,黄刘生.数据结构-用C语言描述.高等教育出版社.1995

[2]孙家启等.C语言程序设计教程.合肥工业大学出版社.2011

[3]晋良颖等.数据结构.人民邮电出版社.2002

                            

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 高考

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1