北邮数据结构实验报告实验三哈夫曼
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
尾。
(4) 重复以上步骤,直到所有待编码串中的字符都编码完毕
(5) 输出编码后的字符串
void Huffman::Encode(char a[],char *d,int n,int j)
//a[]为原始字符串,d 为编码后的哈
夫曼编码字符串,n 为编码表长度,j 为原始字符串的长度
{
for(int m=0;m<j;m++)
第 2页
北京邮电大学信息与通信工程学院
^ 31 8
0
1
^ 16 4
0 ^
15 7
0
1
102 83
^ 76
0
1
100 42
^ 3
0
97 11
5 1
115 20
红色箭头表示父指针,黑色箭头表示孩子指针 由上面的图可知,原字符串编码后的二进制编码为 11101111111111011011011010101010101010100000000000000000 字符串中出现的所有的字符的编码如下:
对编码串解码
输出解码后字符串
第 7页
北京邮电大学信息与通信工程学院
计算编码前后的压缩比 结束
测试条件:输入 I love data Structure, I love Computer。I will try my best to study data Structure.
测试结论:能正确的编码、解码、输出解码后的字符串,并计算出压缩比为 0.518519.
编码的压缩效果。
测试数据: I love data Structure, I love Computer。I will try my best to study data Structure.
提示: 1、用户界面可以设计为“菜单”方式:能够进行交互。 2、根据输入的字符串中每个字符出现的次数统计频度,对没有出现的 字符一律不用编码。
第 4页
北京邮电大学信息与通信工程学院
亲 HTree[i].weight=HTree[x].weight+HTree[y].weight; //新结点的权值为其孩子的权值的和
HTree[i].LChild=x;
HTree[i].RChild=y;
HTree[i].parent=-1;
}
}
时间复杂度:
{
for(int i=0;i<n;i++)
{
if(a[m]==HCodeTable[i].data)
{
d=strcat(d,HCodeTable[i].code);
}
}
}
cout<<"编码后的哈夫曼编码字符串为:"<<d<<endl;
}
时间复杂度:
设待编码字符串长度为 n,编码表中字符个数为 m,则复杂度为 O(n*m)
012345 ASCⅡ 9 115 100 102 103 weight 1 2 4 8 16 3 lchild -1 -1 -1 -1 -1 0 rchild -1 -1 -1 -1 -1 1 parent -5 5 -6 -7 -8 6
678
7 15 31 234 567 780
上结构图中,填充为黄色的部分为写入内存中的部分。每一行的部分为数组的下标,左 边部分为所定义的结构的成员。其中有的结点的父节点的下标是一个负数,用来说明该节点 是该节点的父节点的左孩子,正数说明的是该节点的父节点的右孩子。父节点这零的节点说 明该节点是该哈夫曼树的根节点。画出树的结构如下画所示:(结点中第一个数表示这个字 符的 ASCⅡ编码,第二个数字表示权值)
if(HTree[j].parent==-1) {
if(HTree[j].weight<min1||min2==-1) {
if(min1!=-1)
第 3页
北京邮电大学信息与通信工程学院
{ min2=min1; y=x;
} min1=HTree[j].weight; x=j; } else if(HTree[j].weight<min2||min2==-1) {
北京邮电大学信息与通信工程学院
数据结构实验报告
实验名称:实验三——哈夫曼编/解码器的实现 学生姓名: 侯在鹏 班 级: 2012211120 班内序号: 13 学 号:2012210583 日 期: 2013 年 12 月 10 日
1.实验要求
利用二叉树结构实现赫夫曼编/解码器。 基本要求:
1、初始化(Init):能够对输入的任意长度的字符串 s 进行统计,统计每个 字符的频度,并建立赫夫曼树
4. 总结
本次实验将书上的哈夫曼只是实践在程序中,通过编写,修改等等繁复的工作,我对哈 夫曼树相关知识记得更牢,学的更扎实了。只看书上的只是难以了解很多意想不到的问题。
编写前先看了一遍书,然后在网上看了一些相关知识,最后编写,中间遇到了一些逻辑 错误较为麻烦,其他错误花了一些时间。程序上大体结构较为清晰,功能比较齐全。
2、建立编码表(CreateTable):利用已经建好的赫夫曼树进行编码,并将每 个字符的编码输出。
3、编码(Encoding):根据编码表对输入的字符串进行编码,并将编码后的 字符串输出。
4、译码(Decoding):利用已经建好的赫夫曼树对编码后的字符串进行译码, 并输出译码结果。
5、打印(Print):以直观的方式打印赫夫曼树(选作) 6、计算输入的字符串编码前和编码后的长度,并进行分析,讨论赫夫曼
} } if(sign==0) {
t++; dat[t]=str[m]; wei[t]=1; } } t++; dat[t]='\0'; } 时间复杂度: O(n)
2.3 其他
3. 程序运行结果
主函数流程图: 开始
调用菜单函数
等待用户输入 字符串
利用用户输入的字符串 创建哈夫曼树和编码表
对输入的字符串编码
在选取两个权值最小的结点的函数中要遍历链表,时间复杂度为 O(n),故该函数
的时间复杂度为 O(n^2)
2.2.3 编码函数
算法伪代码:
(1) 从 a 开头的字符开始,逐一对 a 中的字符进行编码
(2)在编码表中查找与当前字符对应的字符
(3)如果找到了与当前字符对应的编码表中的字符,将其编码追加到解码串的末
程序还有很多不足,时间以及个人能力关系,一些功能没有实现,代码上不够简洁,ຫໍສະໝຸດ Baidu 些部分效率低,都有待改进。
第 8页
2.2.5 统计字符权值
算法伪代码: (1) 取出字符串第一个字符,与 data[]中元素比较。若字符与 data[]中元素相同,权值
+1,若不同,则将该字符加入 data[]中。 (2) 取出下一个字符,重复步骤(1)。直到字符串末尾。 源代码: Huffman::Huffman(char str[],char dat[],int wei[],int n,int &t) //str[]为原始字符串,dat[]为 data 数据,wei[]数据相应的权值,n 为字符串长度 {
min2,字符权值赋给 min1,同时改变权值最小的结点编号 x,y.若大于 min1 同时小于 min2, 则将字符权值赋给 min2,改变 y 值。 源代码: void Huffman::SelectMin(int &x,int &y,int a,int b)//选出两个权值最小的结点 { int j,min1,min2; min1=min2=-1; for(j=a;j<b;j++)
t=0;//计数器 dat[t]=str[0]; wei[t]=0; for(int m=0;m<n;m++) {
bool sign=0; for(int x=0;x<t+1;x++) {
if(str[m]==dat[x]) {
wei[x]++; sign=1;
第 6页
北京邮电大学信息与通信工程学院
孩子,i 结点的权值为 x 结点的权值加上 y 结点的权值,i 结点的双亲设置为空 (4) 根据哈夫曼树创建编码表
void Huffman::CreateHTree(int a[],int n) {
HTree=new HNode[2*n-1]; for(int i=0;i<n;i++) {
HTree[i].weight=a[i]; HTree[i].LChild=-1; HTree[i].RChild=-1; HTree[i].parent=-1; } int x,y; for(int i=n;i<2*n-1;i++) { SelectMin(x,y,0,i); //从0~i中选出两个权值最小的结点 HTree[x].parent=HTree[y].parent=i; //用两个权值最小的结点生成新结点,新节点为其双
2.2.4 解码函数
算法伪代码:
(1)得到指向哈夫曼树的根结点的指针和指向待解码串中的第 1 个字符的指针
(2)逐个读取待解码串中的字符,若为 0,则指向哈夫曼树当前结点的指针指向
当前结点的左孩子,若为 1,则指向当前结点的右孩子
(3)指向待解码串的指针指向解码串中的下一个字符,直到指向哈夫曼树结点的
int parent=2*n-1-1;//根结点 while(HTree[parent].LChild!=-1) {
if(*s=='0') parent=HTree[parent].LChild;
else parent=HTree[parent].RChild;
s++; } *d=HCodeTable[parent].data; d++; } } 时间复杂度: 设待解码串长度为 n,则复杂度为 O(n)
a 1110 ; s 1111 ; d 110 ; f 10 ; g 0
2.2 关键算法分析
2.2.1 选择两个最小权值的函数
算法伪代码: (1) 初始化最小权值 min1,min2.可引用变量 x,y。 (2) 遍历哈夫曼树,比较字符的权值与 min1,min2 的大小。若小于 min1,则将 min1 值赋给
min2=HTree[j].weight; y=j; } } } 时间复杂度: 遍历链表,时间复杂度为 O(n)
2.2.2.创建哈夫曼树
算法伪代码: (1)创建一个长度为 2*n-1 的三叉链表 (2)将存储字符及其权值的链表中的字符逐个写入三叉链表的前 n 个结点的 data 域,并将
对应结点的孩子域和双亲域赋为空 (3)从三叉链表的第 n 个结点开始,i=n (3.1)从存储字符及其权值的链表中取出两个权值最小的结点 x,y,记录其下标 x,y。 (3.2)将下标为 x 和 y 的哈夫曼树的结点的双亲设置为第 i 个结点 (3.3)将下标为 x 的结点设置为 i 结点的左孩子,将下标为 y 的结点设置为 i 结点的右
指针的孩子结点为空
(4)如果指向哈夫曼树结点的指针的孩子结点已经为空,则将叶子结点下标对应
第 5页
北京邮电大学信息与通信工程学院
的字符追加到解码串中。 (5)输出解码串 源代码: void Huffman::Decode(char *s,char *d,int n)//解码。s 为编码后的数组,d 为解码 后的数组 { while(*s!='\0') {
2. 程序分析
第 1页
北京邮电大学信息与通信工程学院
2.1 存储结构
程序实现了基本的编解码功能 输入字符串 选择工作目标 编码 解码 相关树,表显示 编码上 根节点向下,左 0 右 1 根据不同字符在尾端相应排位,获得自己的编码,存储。 解码上 依次读取数据 0 或 1,循序寻找, 最后在存储中找到对应编码的字符,输出 再重新读取下一数字开始的数码 在哈夫曼树编码这个程序中,所有数据用的存储结构都是顺序存储结构,其中包括顺序表和 树(三叉树) 树的存储结构如下:(输入的字符串为 assddddffffffffgggggggggggggggg)