赫夫曼编码的应用.docx
《赫夫曼编码的应用.docx》由会员分享,可在线阅读,更多相关《赫夫曼编码的应用.docx(11页珍藏版)》请在冰豆网上搜索。
赫夫曼编码的应用
实验课程名称赫夫曼编码的应用
专业班级10级计科
(1)班
学生姓名
学号
指导教师
2012至2013学年第一学期第1至18周
目录
第1章概述2
第2章系统分析2
2.1分析思想2
2.2需求分析及要求3
2.3研究意义3
第3章概要设计4
3.1设计总图4
第4章 详细设计5
4.1程序中用到的所有抽象数据类型的定义5
4.2主程序模块5
4.3赫夫曼树的建立5
4.4赫夫曼编码5
4.5赫夫曼编码的生成6
4.6赫夫曼树的存储结构描述6
第5章运行与测试7
第6章总结和心得7
参考文献7
伪代码7
第1章概述
在当今信息爆炸时代,如何采用有效的数据压缩技术节省数据文件的存储和计算机网络的传送时间已越来越引起人们的重视,赫夫曼编码正是一种应用广泛且非常有效的数据压缩技术。
第2章系统分析
2.1分析思想
1)巩固赫夫曼树的算法;
2)实现赫夫曼树的建立;
3)赫夫曼编码的生成;
4)赫夫曼文件的译码;
5)运行测试实例。
2.2需求分析及要求
本设计要求对输入的一串电文字符实现赫夫曼编码,再对赫夫曼编码生成的代码串进行译码,输出电文字符串。
通常我们把数据的压缩过程称为编码,解压缩的过程称为解码。
电文编码总长的二进制码形式的字符串。
但在信息传递时,总希望总长度尽可能最短,即采用最短短码。
而设计电文总长最短的二进制前缀编码,就是以n种字符出现的频率作权,构造一颗赫夫曼树,此造构过程称为赫夫曼编码。
2.3研究意义
赫夫曼编码了解:
哈夫曼编码是一种编码方式,以哈夫曼树—即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。
称为赫夫曼编码。
假设每种字符在电文中出现的次数为Wi,编码长度为Li,电文中有n种字符,则电文编码总长度为∑WiLi。
若将此对应到二叉树上,Wi为叶结点的权,Li为根结点到叶结点的路径长度。
那么,∑WiLi恰好为二叉树上带权路径长度。
因此,设计电文总长最短的二进制前缀编码,就是以n种字符出现的频率作权,构造一棵赫夫曼树。
哈弗曼编码使用一张特殊的编码表将源字符进行编码。
这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。
赫夫曼编码的应用很广泛,利用赫夫曼树求得的用于通信的二进制编码称为赫夫曼编码。
树中从根到每个叶子都有一条路径,对路径上的各分支约定:
指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个叶子对应的字符的编码,这就是赫夫曼编码。
第3章概要设计
3.1设计总图
第4章 详细设计
4.1程序中用到的所有抽象数据类型的定义
预定义常量
#defineN50
#defineM2*N-1
#defineMAXSIZE100
输入输出语句
输入语句scanf([格式串],变量1,变量2,。
。
。
。
。
变量n);
输出语句printf([格式串],变量1,变量2,。
。
。
。
。
变量n);
赋值语句变量名=表达式;
循环语句for(赋初值表达式序列;条件;修改表达式序列)
结束语句return表达式;
类型定义Typedefintstatus
4.2主程序模块
其中主函数为:
main(){
定义以及初始化
从文件中读取数据,输出矩阵
调用转置和加法函数,输出转置矩阵以及加法矩阵
}
4.3赫夫曼树的建立
1.选择parent为0且权值最小的两个根结点的算法
2.统计字符串中字符的种类以及各类字符的个数
3.构造赫夫曼树
4.赫夫曼树的存储
5.赫夫曼编码的算法
6.建立正文的编码文件
4.4赫夫曼编码
要求电文的赫夫曼编码,必须先定义赫夫曼编码类型,根据设计要求和实际需要定义的类型如下:
typedefstruct
{
chara[N];
intstart;
}HCode;
进行赫夫曼编码译码之前建立赫夫曼二叉树,新建立赫夫曼树,建立赫夫曼编码,进行主函数时,输入A到F所有的字符,并输入其权值,将其进行编码;将data的权值赋给ht,判断结点是否大于1,输出根结点及权值。
比较i<2*N-1;若是调用调用SELECT函数算出算出父亲结点然后输出两子结点及父亲结点。
4.5赫夫曼编码的生成
1.建立赫夫曼树的三个函数
voidselect(HuffmanTreeT,intk,int&s1,int&s2){}
2.生成赫夫曼编码文件的两个函数
voidHuffmanEncoding(HuffmanTreeHT,HuffmanCodeHC){}
3.电文的译码
char*decode(HuffmanCodeHC){}
4.6赫夫曼树的存储结构描述
#defineN100//叶子结点数
#defineM2*N-1//赫夫曼树中结点总数
typedefstruct{
intweight;//叶子结点的权值
intlchild,rchild,parent;//左右孩子及双亲指针
}HTNode;//树中结点类型
第5章运行与测试
第6章总结和心得
在做本次试验之前我阅读了数据结构课程设计中关于赫夫曼的应用这一章节知识,在编写这个程序之前,我复习之前学习的基本知识,赫夫曼最小路径的求法,赫夫曼编码及译码的范围,程序结构等相关问题。
还上网查阅了相关知识,了解到什么是赫夫曼树,什么是赫夫曼编码等问题,还去了解电文的编码、译码问题等来加深对它们的理解,还查阅了关于“树”的内容。
通过这次的课程设计,让我在程序编写上有了很大的,提高感觉到了程序设计真的很锻炼人,自己要学会慢慢的摸索路径,这样形成自己编程时的特色。
一个成功的程序,要经过之前对课题的反复思考。
这次我运用的是数组存储类型,结构简单而且方便。
通过运用for的多重循环,提高运行的效率。
参考文献
[1]数据结构:
严蔚敏,吴伟民编著.—北京:
清华大学出版社,2007
[2]数据结构与算法分析:
苏仕华编著.—合肥:
中国科学技术大学出版社,2004
[3]数据结构课程设计:
苏仕华编著.—北京:
清华大学出版社,2002
[4]徐孝凯.数据结构简明教程[M].清华大学出版社,1995年
伪代码
#include
#include
#include
#include
typedefstruct{
unsignedintweight;
unsignedintparent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配赫夫曼树
typedefchar**HuffmanCode;//动态分配数组存储赫夫曼编码表
intx[27],y[9],count;
voidSelectDifferentChar(intw[],int&n);//将输入的字符串中相同的字符删去
voidHuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,intw[],intn);
voidSelect(HuffmanTreeHT,intn,int&s1,int&s2);
voidScanfCrunode(intw[],charz[],int&n);//读入结点,并将权值存到*w数组中
voidPrintHuffmanCode(HuffmanCodeHC,intw[],intn,floateve);
voidEverage(float&eve,intw[],intn,HuffmanCodeHC);
voidmain()
{
HuffmanTreeHT;
HuffmanCodeHC;
intw[254],n;
charz[27];
floateve=0;
printf("请输入字符串:
\n");
ScanfCrunode(w,z,n);
SelectDifferentChar(w,n);
HuffmanCoding(HT,HC,w,n);
Everage(eve,w,n,HC);
PrintHuffmanCode(HC,w,n,eve);
}
voidScanfCrunode(intw[],charz[],int&n)//读入结点,并将权值存到*w数组中
{
inti;
gets(z);
count=n=strlen(z);
if(n<=1)
{printf("wrongdata\n");
exit(0);
}
for(i=0;iw[i]=z[i];
}
voidHuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,intw[],intn)//赫夫曼编码
{intm,i,s1,s2,start,f,c;
char*cd;
m=2*n-1;
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号单元没用
for(i=1;i<=n;i++)
{HT[i].weight=w[i-1];
HT[i].parent=0;
HT[i].rchild=0;
HT[i].lchild=0;
}
for(;i<=m;i++)
{HT[i].weight=0;
HT[i].parent=0;
HT[i].rchild=0;
HT[i].lchild=0;
}
for(i=n+1;i<=m;i++)
{
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=(HuffmanCode)malloc((n+1)*sizeof(char*));
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));
strcpy(HC[i],&cd[start]);}
free(cd);
}
voidSelect(HuffmanTreeHT,intn,int&s1,int&s2)
{inti,j,k;
k=32767;//无符号整数最大值
for(i=1;i<=n;i++)
if(HT[i].weight{
j=i;
k=HT[i].weight;
}
s1=j;
k=32767;
for(i=1;i<=n;i++)
if(HT[i].weight=s1)
{
j=i;
k=HT[i].weight;
}
s2=j;
}
voidSelectDifferentChar(intw[],int&n)
{inti,j,d=0,k;
for(i=0;iy[i]=w[i];
for(i=0;ifor(j=i+1;jif(w[i]==w[j])
w[j]=-1;
for(i=0;iif(w[i]!
=-1){
x[d]=w[i];
d++;
}
k=n;
n=d;
for(i=0;i{d=0;
for(j=0;jif(x[i]==y[j])
d++;
w[i]=d;
}
if(n<=1)
{printf("wrongdata\n");
exit(0);
}
}
voidEverage(float&eve,intw[],intn,HuffmanCodeHC)
{intsum=0,i;
for(i=0;isum+=w[i];
for(i=0;ieve+=((float)w[i]/sum)*strlen(HC[i+1]);
}
voidPrintHuffmanCode(HuffmanCodeHC,intw[],intn,floateve)
{inti,j,k;
for(i=0;iprintf("%c编码为:
",x[i]);
puts(HC[i+1]);
printf("出现次数为%d",w[i]);
printf("\n");
}
printf("平均编码长度为:
%.2f\n",eve);
printf("译文如下\n");
for(i=0;ifor(j=0;jif(y[i]==x[j])
for(k=0;kprintf("%c",HC[j+1][k]);
printf("\n");
}