哈夫曼编码的实现.docx
- 文档编号:9053367
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:19
- 大小:146.69KB
哈夫曼编码的实现.docx
《哈夫曼编码的实现.docx》由会员分享,可在线阅读,更多相关《哈夫曼编码的实现.docx(19页珍藏版)》请在冰豆网上搜索。
哈夫曼编码的实现
哈夫曼编码的实现
张zhaohan10804XXXXX
2010/6/12
自拟问题
利用哈夫曼编码进行信息通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
试为这样的信息传输写一个哈夫曼编/译码系统。
系统设计
(一)设计目标
一个完整的系统应具有以下功能:
●:
初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
输出哈夫曼树,及各字符对应的编码。
●W:
输入(Input)。
从终端读入需要编码的字符串s,将字符串s存入文件Tobetran.txt中。
●E:
编码(Encoding)与译码(Decoding)。
编码(Encoding)。
利用已建好的哈夫曼树(如不在内存,则从文件htmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
译码(Decoding)。
利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
印代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码写入文件CodePrint中。
●T:
印哈夫曼树(TreePrinting)。
将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
5)Q:
退出程序。
返回WINDOWS界面。
(二)设计思想
哈夫曼编码(HuffmanCoding)是一种编码方式,以哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。
是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。
这种方法是由David.A.Huffman发展起来的。
例如,在英文中,e的出现概率很高,而z的出现概率则最低。
当利用哈夫曼编码对一篇英文进行压缩时,e极有可能用一个位(bit)来表示,而z则可能花去25个位(不是26)。
用普通的表示方法时,每个英文字母均占用一个字节(byte),即8个位。
二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。
倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。
(三)系统模块划分
哈夫曼编/解码器的程序结构图
●初始化算法:
程序从文件abc.txt中获取26个英文字母的权值。
●编码算法:
(1)对输入的一段欲编码的字符串进行统计各个字符出现的次数,并它们转化为权值{w1,w2,……,wN}构成n棵二叉树的集合F={T1,T2,……,Tn}把它们保存到结构体数组HT[n]中,其中{Ti是按它们的ASCⅡ码值先后排序。
其中每棵二叉树Ti中只有一个带权为Wi的根结点的权值为其左、右子树上根结点的权值之和。
(2)在HT[1..i]中选取两棵根结点的权值最小且没有被选过的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为左、右子树上根结点的权值之和。
(3)哈夫曼树已经建立后,从叶子到根逆向求每一个字符的哈夫曼编码。
●译码算法:
译码的过程是分解电文中字符串,从根出发,按字符'0',或'1'确定找左孩子或右孩子,直至叶子结点,便求的该子串相应字符并输出接着下一个字符。
(四)数据结构与算法描述
typedefstruct
{intweight;
intparent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配数组存储赫夫曼树
typedefchar**HuffmanCode;//动态分配数组存储赫夫曼编码表
intmin(HuffmanTreet,inti)//---------求赫夫曼编码-------------
voidselect(HuffmanTreet,inti,int&s1,int&s2)//----slect函数----
voidHuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,int*w,intn)
//w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC
voidInitialization()//----------初始化赫夫曼链表--------------
voidInputCode()//---------获取报文并写入文件-------------
voidEncoding()//----------------编码函数------------------
voidDecoding()//-----------------译码函数-----------------
voidCode_printing()//-------------打印编码的函数--------------
voidcoprint(HuffmanTreestart,HuffmanTreeHT)
//------------------------打印赫夫曼树的函数-----------------------
voidmain()//--------------------主函数-------------------
(五)测试结果与分析
A
80
B
15
C
30
D
40
E
130
F
20
G
15
H
60
I
65
J
5
K
5
L
35
M
30
N
70
O
80
P
20
Q
2
R
65
S
60
T
90
U
30
V
10
W
15
X
5
Y
20
Z
2
abc.txt文件中的字母和权值
声明:
程序预先将Huffman编码解码所需的26个字母和权值保存在根目录下的abc.txt文件下。
初始化后程序对abc.txt文件中的数据进行读取并运行编码函数进行哈夫曼编码。
然后将字母、权值和哈夫曼编码存在根目录下的htmTree.txt文件中。
在屏幕显示出字符、权值、编码。
输入w进入待编码字符输入窗口,并键入字符串(注意单词间无空格)“thisprogramismyfavorite”。
可以看出所获得的字符串已经存入根目录下的tobetran.txt文件中。
输入e进行编码、译码和打印编码功能。
输入t打印哈夫曼树。
由于哈夫曼树过于巨大,一次截屏无法完全显示,使用两次截屏。
以上两幅图显示出来程序编出的哈夫曼树的形状。
打印出来的图形与教科书上的常见哈夫曼树略有不同,左边的数是右边数的父节点。
输入q退出程序。
附录程序源代码
#include
#include
#include
#include
#include
#include
#include
constintUINT_MAX=10000;
typedefstruct
{
intweight;
intparent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配数组存储赫夫曼树
typedefchar**HuffmanCode;//动态分配数组存储赫夫曼编码表
//--------------------全局变量-----------------------
HuffmanTreeHT;
HuffmanCodeHC;
int*w,i,j;
constintn=26;
char*z;
intflag=0;
intnumb=0;
//-----------------求赫夫曼编码---------------------
intmin(HuffmanTreet,inti)
{//此函数将要被voidselect()调用
intj,flag;
intk=UINT_MAX;//取k为不小于可能的值
for(j=1;j<=i;j++)
if(t[j].weight k=t[j].weight,flag=j; t[flag].parent=1; returnflag; } //--------------------slect函数---------------------- voidselect(HuffmanTreet,inti,int&s1,int&s2) {//s1为最小的两个值中序号小的那个 intj; s1=min(t,i); s2=min(t,i); if(s1>s2) { j=s1; s1=s2; s2=j; } } //-------------------参考课本算法6.12------------------- voidHuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,int*w,intn) {//w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC intm,i,s1,s2,start; intc,f; HuffmanTreep; char*cd; if(n<=1) return;//检测结点数是否可以构成树 m=2*n-1; HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号单元未用 for(p=HT+1,i=1;i<=n;++i,++p,++w) { p->weight=*w; p->parent=0; p->lchild=0; p->rchild=0; } for(;i<=m;++i,++p) p->parent=0; for(i=n+1;i<=m;++i)//建赫夫曼树 {//在HT[1~i-1]中选择parent=0且weight最小的两个结点,其序号分别为s1和s2 select(HT,i-1,s1,s2); HT[s1].parent=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*)); //分配n个字符编码的头指针向量([0]不用) 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)); //为第i个字符编码分配空间 strcpy(HC[i],&cd[start]);//从cd复制编码(串)到HC } free(cd);//释放工作空间 } //----------------------初始化赫夫曼链表------------------------- voidInitialization() { flag=1; intnum2; cout<<"下面初始化赫夫曼链表"< w=(int*)malloc(n*sizeof(int));//为第26个字符权值分配空间 z=(char*)malloc(n*sizeof(char));//为第26个字符分配空间 cout<<"\n依次显示"< charbase[2];//? ifstreamfin("abc.txt"); for(i=0;i { fin>>base; *(z+i)=*base;//? fin>>num2;//上面123行 *(w+i)=num2; } HuffmanCoding(HT,HC,w,n); //----------------------------------打印编码--------------------------------------- cout<<"字符"< for(i=1;i<=n;i++) { cout< cout< } //--------------------------将赫夫曼编码写入文件---------------------------- cout<<"下面将赫夫曼编码写入文件"< FILE*htmTree; charr[]={'','\0'}; if((htmTree=fopen("htmTree.txt","w"))==NULL) { cout<<"不能打开文件"< return; } for(i=0;i { fputc(*(z+i),htmTree); fputs(r,htmTree); } for(i=0;i { fprintf(htmTree,"%6d",*(w+i)); fputs(r,htmTree); } for(i=1;i<=n;i++) { fputs(HC[i],htmTree); fputs(r,htmTree); } fclose(htmTree); cout<<"已将字符与对应编码写入根目录下文件htmTree.txt中"< } //--------------------------获取报文并写入文件--------------------------- voidInputCode() { FILE*tobetran; charstr[100]; if((tobetran=fopen("tobetran.txt","w"))==NULL) { cout<<"不能打开文件"< return; } cout<<"请输入你想要编码的字符"< gets(str); fputs(str,tobetran); cout<<"获取报文成功"< fclose(tobetran); cout<<"...................."< } //---------------------------------编码函数--------------------------------- voidEncoding() { cout<<"下面对目录下文件tobetran.txt中的字符进行编码"< FILE*tobetran,*codefile; if((tobetran=fopen("tobetran.txt","rb"))==NULL) { cout<<"不能打开文件"< } if((codefile=fopen("codefile.txt","wb"))==NULL) { cout<<"不能打开文件"< } char*tran; i=99; tran=(char*)malloc(100*sizeof(char)); while(i==99) { if(fgets(tran,100,tobetran)==NULL) { cout<<"不能打开文件"< break; } for(i=0;*(tran+i)! ='\0';i++) { for(j=0;j<=n;j++) { if(*(z+j-1)==*(tran+i)) { fputs(HC[j],codefile); if(j>n) { cout<<"字符错误,无法编码! "< break; } } } } } cout<<"…………编码完成…………"< cout<<"编码写入目录下的codefile.txt中"< fclose(tobetran); fclose(codefile); free(tran); } //-------------------------译码函数--------------------------- voidDecoding() { cout<<"下面对根目录下文件codefile.txt中的字符进行译码"< FILE*codef,*txtfile; if((txtfile=fopen("\\Textfile.txt","w"))==NULL) { cout<<"不能打开文件"< } txtfile=fopen("Textfile.txt","w"); if((codef=fopen("codefile.txt","r"))==NULL) { cout<<"不能打开文件"< } codef=fopen("codefile.txt","r"); char*work,*work2,i2; inti4=0,i,i3; unsignedlonglength=10000; work=(char*)malloc(length*sizeof(char)); fgets(work,length,codef); work2=(char*)malloc(length*sizeof(char)); i3=2*n-1; for(i=0;*(work+i-1)! ='\0';i++) { i2=*(work+i); if(HT[i3].lchild==0) { *(work2+i4)=*(z+i3-1); i4++; i3=2*n-1; i--; } elseif(i2=='0')i3=HT[i3].lchild; elseif(i2=='1')i3=HT[i3].rchild; } *(work2+i4)='\0'; fputs(work2,txtfile); cout<<"…………译码完成…………"< cout<<"内容写入根目录下的文件textfile.txt中"< free(work);//释放工作区 free(work2);//释放工作区 fclose(txtfile);//关闭文件txtfile.txt fclose(codef);//关闭文件codef.txt } //-----------------------打印编码的函数---------------------- voidCode_printing() { cout<<"下面打印根目录下文件CodePrin.txt中编码字符"< FILE*CodePrin,*codefile; if((CodePrin=fopen("CodePrin.txt","w"))==NULL) { cout<<"不能打开文件"< return; } if((codefile=fopen("codefile.txt","r"))==NULL) { cout<<"不能打开文件"< return; } char*work3; work3=(char*)malloc(51*sizeof(char)); if(fgets(work3,51,codefile)==NULL) { cout<<"不能读取文件"< } else do { fputs(work3,CodePrin); puts(work3); }while(strlen(work3)==50&&fgets(work3,51,codefile)! =NULL); free(work3); cout<<"打印结束"< fclose(CodePrin); fclose(codefile); } //------------------------打印赫夫曼树的函数----------------------- voidcoprint(HuffmanTreestart,HuffmanTreeHT)//start=ht+26这是一个递归算法 { if(start! =HT) { FILE*TreePrint; if((TreePrint=fopen("TreePrint.txt","a"))==NULL) { cout<<"创建文件失败"< return; } numb++;//number=0该变量为已被声明为全局变量 coprint(HT+start->rchild,HT);//递归先序遍历 cout< fprintf(TreePrint,"%d\n",start->weight); coprint(HT+start->lchild,HT); numb--; fclose(TreePrint); } } voidTree_printing(HuffmanTreeHT,intw) { HuffmanTreep; p=HT+w;//p=HT+26 cout<<"下面打印赫夫曼树"< coprint(p,HT);//p=HT+26
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 哈夫曼 编码 实现