北邮数据结构实验三题目2哈夫曼树.docx

上传人:b****6 文档编号:5247669 上传时间:2022-12-14 格式:DOCX 页数:19 大小:224.90KB
下载 相关 举报
北邮数据结构实验三题目2哈夫曼树.docx_第1页
第1页 / 共19页
北邮数据结构实验三题目2哈夫曼树.docx_第2页
第2页 / 共19页
北邮数据结构实验三题目2哈夫曼树.docx_第3页
第3页 / 共19页
北邮数据结构实验三题目2哈夫曼树.docx_第4页
第4页 / 共19页
北邮数据结构实验三题目2哈夫曼树.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

北邮数据结构实验三题目2哈夫曼树.docx

《北邮数据结构实验三题目2哈夫曼树.docx》由会员分享,可在线阅读,更多相关《北邮数据结构实验三题目2哈夫曼树.docx(19页珍藏版)》请在冰豆网上搜索。

北邮数据结构实验三题目2哈夫曼树.docx

北邮数据结构实验三题目2哈夫曼树

数据结构实验报告

实验名称:

实验三题目2哈夫曼树

学生姓名:

班级:

班内序号:

学号:

日期:

1.实验要求

实验目的:

Ø熟悉C++语言的基本编程方法,掌握集成编译环境的测试方法

Ø学习指针、模板类、异常处理的使用

Ø掌握线性表的操作实现方法

Ø培养使用线性表解决实际问题的能力

实验内容:

利用二叉树结构实现赫夫曼编/解码器。

基本要求:

1、初始化(Init):

能够对输入的任意长度的字符串s进行统计,统计每个字符的频度,并建立赫夫曼树

2、建立编码表(CreateTable):

利用已经建好的赫夫曼树进行编码,并将每个字符的编码输出。

3、编码(Encoding):

根据编码表对输入的字符串进行编码,并将编码后的字符串输出。

4、译码(Decoding):

利用已经建好的赫夫曼树对编码后的字符串进行译码,并输出译码结果。

5、打印(Print):

以直观的方式打印赫夫曼树(选作)

6、计算输入的字符串编码前和编码后的长度,并进行分析,讨论赫夫曼编码的压缩效果。

测试数据:

IlovedataStructure,IloveComputer。

IwilltrymybesttostudydataStructure.

提示:

1、用户界面可以设计为“菜单”方式:

能够进行交互。

2、根据输入的字符串中每个字符出现的次数统计频度,对没有出现的

字符一律不用编码。

2.程序分析

2.1存储结构

二叉树:

示意图:

root

lchildparentrchild

(静态三叉链表存储)

weight

LChild

RChild

parent

0

2

-1

-1

-1

1

3

-1

-1

-1

2

6

-1

-1

-1

3

9

-1

-1

-1

4

-1

-1

-1

5

-1

-1

-1

6

-1

-1

-1

(a)初始化哈夫曼树

 

weight

LChild

RChild

parent

0

2

-1

-1

4

1

3

-1

-1

4

2

6

-1

-1

5

3

9

-1

-1

6

4

5

0

1

5

5

11

4

2

6

6

20

3

5

-1

(b)创建好的哈夫曼树

 

哈夫曼编码的存储结构

data

code

0

Z

100

1

C

101

2

B

11

3

A

0

01

01

01

 

2.2关键算法分析

1初始化

算法步骤:

①统计字符串字符综述并申请动态数组存储字符串;

②对所存储字符串进行排序;

③统计不同字符的个数;

④释放动态内存空间;

⑤创建哈夫曼数的数组;

⑥创建哈夫曼编码表。

源代码:

voidHuffman:

:

Init(char*s)

{

intn=0;

while(*(s+n)!

='\0')

{

n++;//统计字符串字符数

}

char*temp=newchar[n];//申请动态数组存储字符串以便之后对字符串排序

for(inti=0;i

{

temp[i]=*(s+i);

}

charctemp;

for(inti=0;i

{

for(intj=0;j

{

if(temp[j]>temp[j+1])

{

ctemp=temp[j];

temp[j]=temp[j+1];

temp[j+1]=ctemp;

}

}

}

intk=1;

for(inti=1;i

{

if(temp[i]!

=temp[i-1])

{

k++;

}

}

HTree=newHNode[2*k-1];

m=2*k-1;//存储哈夫曼数组大小

intl=0;//统计不同字符出现的频度

k=0;//控制哈夫曼数组下标

ctemp=temp[0];//做标记

for(inti=0;i

{

if(temp[i]==ctemp)

{

l++;//统计不同字符出现的频度

if(i==n-1)

HTree[k].weight=l;

}

else

{

HTree[k].c=ctemp;

HTree[k].weight=l;

ctemp=temp[i];

k++;

l=1;

HTree[k].c=ctemp;

HTree[k].weight=l;

}

}

delete[]temp;//释放动态内存空间

Creat();//创建哈夫曼数的数组

CodeTable();//创建哈夫曼编码表

}

时间复杂度:

n

2创建哈夫曼树动态数组

算法步骤:

①根据权重数组初始化哈夫曼树;

②选取权值最小的两个结点作为左右子树,构成一个新的二叉树,其根结点的权值取左右子树权值之和;

③删除这两棵子树,将新构成的树加入到T中,重复②③直至T中只含有一棵树。

源代码:

voidHuffman:

:

Creat()

{

intn=(m+1)/2;//n表示不同字符的个数

for(inti=0;i

{

HTree[i].LChild=-1;

HTree[i].RChild=-1;

HTree[i].parent=-1;

}

intx,y;

for(inti=n;i<2*n-1;i++)

{

SelectMin(x,y,i);//找出最小权重的两个字符

HTree[x].parent=i;

HTree[y].parent=i;

HTree[i].weight=HTree[x].weight+HTree[y].weight;

HTree[i].LChild=x;

HTree[i].RChild=y;

HTree[i].parent=-1;

}

}

时间复杂度:

n

3寻找权值最小的两个数

算法步骤:

①首先判断根结点是否是最小,若不是,则继续判断;

②依次对各个结点进行判断,找出最小结点;

③找出最小权重结点后将最小节点放置在无法再次访问的位置,再进行次小值的判断。

源代码:

voidHuffman:

:

SelectMin(int&x,int&y,inti)

{

x=0;

while(HTree[x].parent!

=-1)//防止第一个就是之前找到的最小的导致下面循环无效

{

x++;

}

for(intj=1;j

{

if(HTree[j].parent!

=-1)

{

continue;

}

x=(HTree[x].weight<=HTree[j].weight)?

x:

j;

}

HTree[x].parent=-2;//防止y重复

y=0;

while(HTree[y].parent!

=-1)

{

y++;

}

for(intj=1;j

{

if(HTree[j].parent!

=-1)

{

continue;

}

y=(HTree[y].weight<=HTree[j].weight)?

y:

j;

}

}

时间复杂度:

n

4生成哈夫曼编码表

算法步骤:

①申请与不同字符个数对应的动态空间,以存储不同字符代表的编码;

②自下而上判断,左孩子则编码'0',右孩子则编码'1',到达根节点之后结束循环;

③字符编码串最后添加结束符,结束编码;

④颠倒字符串。

源代码:

voidHuffman:

:

CodeTable()

{

intn=(m+1)/2;

HcodeTable=newHCode[n];//申请与不同字符个数对应的动态空间,以存储不同字符代表的编码

for(inti=0;i

{

HcodeTable[i].data=HTree[i].c;

intchild=i;

intparent=HTree[i].parent;//用于判断

intk=0;

while(parent!

=-1)//自下而上到达根节点之后结束循环

{

if(child==HTree[parent].LChild)//左孩子则编码'0'

HcodeTable[i].code[k]='0';

else

HcodeTable[i].code[k]='1';//右孩子则编码'1'

k++;

child=parent;

parent=HTree[child].parent;

}

HcodeTable[i].code[k]='\0';//字符编码串最后添加结束符

Reverse(HcodeTable[i].code);//由于自上而下因此需要颠倒字符串

}

}

时间复杂度:

n

5颠倒字符串

算法步骤:

①统计字符串字符个数;

②将第i个字符与第n-i个进行交换。

voidHuffman:

:

Reverse(charc[])

{

intn=0;

chartemp;

while(c[n+1]!

='\0')//统计字符个数

{

n++;

}

for(inti=0;i<=n/2;i++)

{

temp=c[i];

c[i]=c[n-i];

c[n-i]=temp;

}

}

时间复杂度:

n

6编码函数

算法步骤:

①将输入的字符串与编码表中的比较,字符串尾停止,如果相等,则对字符进行编码,并对每个字符的编码进行输出;

②编码的同时统计编码的总字节数;

③计算哈夫曼编码压缩比。

voidHuffman:

:

Encode(char*s,string*d)

{

floatsum=0;//统计字节数

intn=0;

while(*s!

='\0')

{

for(inti=0;i<(m+1)/2;i++)

{

if(*s==HTree[i].c)

{

cout<

for(intj=0;HcodeTable[i].code[j]!

='\0';j++)

{

*d+=HcodeTable[i].code[j];

sum+=1;

}

s++;

n++;

break;

}

}

}

cout<<"压缩比为:

"<

}

时间复杂度:

n

7解码函数

算法步骤:

①从根节点开始进行解码,如果字符为0,则为左孩子,1,则为右孩子;

②编码匹配编码表中对应的数据,进行解码。

源代码:

voidHuffman:

:

Decode(char*s,char*d)

{

while(*s!

='\0')

{

intparent=m-1;//根结点

while(HTree[parent].LChild!

=-1)//从根节点开始直到终端结点结束循环

{

if(*s=='0')

parent=HTree[parent].LChild;

else

parent=HTree[parent].RChild;

if(*s=='\0')//不解码码串最尾部,没有编码的部分

{

return;

}

s++;

}

*d=HcodeTable[parent].data;

d++;

}

}

时间复杂度:

n

 

2.3其他

1判断最小权值的函数还可以简化为一个循环;

2没有直观地画出哈夫曼树,用户只能通过哈夫曼编码表进行解码。

 

3.程序运行结果

1、测试主函数流程

 

 

3

12

 

 

2测试结果如图

4.总结

1、出现的问题及解决办法

编写最小权值函数时,寻找到的最小值是一样的,原因是寻找次小值的过程中,重复了寻找最小值的过程,造成重复,之后在寻找到最小值后将其父结点更改,使接下来的寻找过程不再考虑它

2、心得体会

进一步了解哈夫曼树的思想和相关概念,锻炼了使用二叉树解决实际问题的能力

3、下一步的改进

将查找权值最小的两个数的函数由2个循环改进为一个循环,简便算法;

直观地画出哈夫曼树,使用户更加清晰地认识编码结构。

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

当前位置:首页 > 高等教育 > 艺术

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

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