哈夫曼编码译码系统.docx
- 文档编号:27883745
- 上传时间:2023-07-06
- 格式:DOCX
- 页数:48
- 大小:230.26KB
哈夫曼编码译码系统.docx
《哈夫曼编码译码系统.docx》由会员分享,可在线阅读,更多相关《哈夫曼编码译码系统.docx(48页珍藏版)》请在冰豆网上搜索。
哈夫曼编码译码系统
《数据结构》课程设计
6.5电文的编码和译码
姓名:
XXX
院系:
计算机学院
专业:
计算机科学与技术
年级:
13级
学号:
E11314XXX
指导教师:
XXX
2015年10月30日
1.课程设计的目的
(1)熟练使用C语言编写程序,解决实际问题;
(2)了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;
(3)初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;
(4)提高综合运用所学的理论知识和方法独立分析和解决问题的能力。
2.需求分析
(1)为信息收发站写一个哈夫曼编/译码系统。
(2)要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
(3)要求可以将哈夫曼树以树状或凹入法打印到屏幕。
3电文的编码和译码的设计
3.1概要设计
3.1.1主界面设计
图1
主界面,如图1所示,包含初始化,编码,译码,代码文件,哈夫曼树五个菜单。
其中,菜单1用来从终端读入n个字符和n个权值,建立哈夫曼树,并将它存于文件中;菜单2用来利用已建好的哈夫曼树,对文件中或直接输入的正文进行编码,然后将结果存入文件中,如果哈夫曼树不在内存可通过初始化或文件读入到内存;菜单3利用已建好的哈夫曼树将文件中的代码进行译码,译码结果存入文件中,若哈夫曼树不在内存中,处理方式与菜单2相同;菜单4将编码文件以紧凑格式显示在终端上,每行50个代码,同时将此字符形式的编码写入文件中;菜单5将已在内存中的哈夫曼树以凹入法显示在终端上。
3.1.2存储结构
这里使用了4个结构体。
结构体HTNode存放哈夫曼树的结点,包含权值weight,以及父节点parent、左孩子lchild、右孩子rchild所在位置。
结构体Huffmantree保存哈夫曼树,其中num是结点数,参与哈夫曼编码的各个字符alphabet[],hftree[]是HTNode类型存放构建的哈夫曼树的表,HCnum[]是每个字符编码的长度,HC[][]是编码字符数组。
结构体Text保存正文,其中num存放正文的长度,content存放正文内容。
Code存放编码结果,num是编码长度,bin是编码内容。
3.1.3系统功能设计
本系统的功能描述如下:
1可输入字符和其对应的权值,以构建哈夫曼树。
2可输入或读入正文,根据构建的哈夫曼树,对正文进行编码,若哈夫曼树未存在,可从文件中读入或者初始化输入,若正文中字符在哈夫曼树中不存在,则会提示编码出错。
3可读入编码文件,根据存在的哈夫曼树,对文件进行解码,若哈夫曼树不存在会进行和2一样的操作,若解码时,编码在哈夫曼树中不存在,则提示解码出错。
4可根据内存中的哈夫曼树用凹入表示法输出树形界面。
3.2详细设计
3.2.1系统子程序及功能设计
本系统设置32个函数,函数名及功能说明如下:
voidHufftreeInit(Huffmantree&H)//对结构体Huffmantree初始化
voidHufftreeMalloc(Huffmantree&H,intnum)//给结构体Huffmantree分配空间
voidTextInit(Text&c)//结构体Text初始化
voidTextMalloc(Text&c,intnum)//给结构体Text分配存储空间
voidCodeInit(Code&co)//给结构体code初始化
voidCodeMalloc(Code&co,intnum)//给结构体code分配存储空间
intinputselection(intn)//输入菜单选择,返回值为输入的选项
intTreeRead(Huffmantree&H)//读取哈夫曼树文件
intTreeSave(HuffmantreeH)//保存结构体Huffmantree
intTextSave(Textc)//保存结构体Text
intTextRead(Text&c)//读取结构体Text
intCodeSave(Code&co)//保存结构体Code
intCodeSave2(Code&co)//以紧凑形式保存结构体Code
intCodeRead(Code&co)//读取结构体Code
intistrue()//判断是否输入了Y
voidexchange(ints[])//交换s[0]和s[1]中的内容
voidSelect(HTNodeHT[],inti,ints[])//找到parent为0且weight最小的两个结点,序号放在s[0]和s[1]
voidHuffmancoding(Huffmantree&HT)//哈弗曼编码
intexist(HuffmantreeHT,intindex)//判断HT.alphabet[index]是否与其他结点重复
voidinitialization(Huffmantree&HT)//初始化
intencodingcourse()//编码菜单
voidinputtext(Text&text)//输入正文
voidencode(HuffmantreeHT,Texttext)//编码保存至文件
voidencoding(Huffmantree&HT)//编码菜单
intdecodingcourse()//解码菜单
char*substring(Codeco,intbeginning,intending)//求子串,从beginning到ending
voiddecode(HuffmantreeHT)//解码
voiddecoding(Huffmantree&HT)//解码菜单
voidprint()//印代码文件
intmaincourse()//主菜单
voidwelcom()//欢迎界面
voidtreeprinting(HuffmantreeHT,intindex,intlevel,char*filename,intfla)//凹入法印哈夫曼树
voidhfmtreeprinting(HuffmantreeHT){//用凹入法印哈弗曼树,包含文件输入
各主要函数之间的调用关系如下:
(见下页)
3.2.2数据类型定义
structHTNode{//哈夫曼树的结点
Elemtypeweight;
intparent,lchild,rchild;
};
structHuffmantree{//哈夫曼树
intnum;
char*alphabet;//字符数组
HTNode*hftree;//结点数组
int*HCnum;//每个字符对应编码的长度
BIN**HC;//每个字符的编码
};
structText{//正文
intnum;//正文长度
char*content;//正文
};
structCode{//编码,用字符型数字表示
intnum;//编码长度
BIN*bin;//编码
};
3.2.3系统主要子程序详细设计
哈夫曼编码:
voidexchange(ints[])//交换s[0]和s[1]中的内容
{
inttemp;
temp=s[0];
s[0]=s[1];
s[1]=temp;
}
voidSelect(HTNodeHT[],inti,ints[])
{//找到parent为0且weight最小的两个结点,序号放在s[0]和s[1]
intj,flag=0;
for(j=1;j<=i&&flag<2;j++)
if(!
HT[j].parent)
s[flag++]=j;
if(HT[s[0]].weight>HT[s[1]].weight)
exchange(s);
for(;j<=i;j++)
{
if(!
HT[j].parent)
if(HT[j].weight { s[1]=j; if(HT[s[0]].weight>HT[s[1]].weight) exchange(s); } } } voidHuffmancoding(Huffmantree&HT)//哈弗曼编码 { intm,i,start,f,n=HT.num; ints[2]; unsignedc; char*cd; m=2*n-1; for(i=n+1;i<=m;i++) { Select(HT.hftree,i-1,s); HT.hftree[s[0]].parent=i; HT.hftree[s[1]].parent=i; HT.hftree[i].lchild=s[0]; HT.hftree[i].rchild=s[1]; HT.hftree[i].parent=0; HT.hftree[i].weight=HT.hftree[s[0]].weight+HT.hftree[s[1]].weight; } cd=(char*)malloc(n*sizeof(char)); cd[n-1]='\0'; for(i=1;i<=n;i++) { start=n-1; for(c=i,f=HT.hftree[i].parent;f! =0;c=f,f=HT.hftree[f].parent) { if(HT.hftree[f].lchild==c)cd[--start]='0'; elsecd[--start]='1'; } HT.HC[i]=(char*)malloc((n-start)*sizeof(char)); strcpy(HT.HC[i],&cd[start]); HT.HCnum[i]=strlen(HT.HC[i]); } free(cd); } 给正文编码: voidencode(HuffmantreeHT,Texttext){//编码保存至文件 system("cls"); Codec; cout<<"--------------------------------\n"; cout<<"正文编码\n"; cout<<"--------------------------------\n"; if(HT.num==0){ cout<<"哈夫曼树不存在,请初始化或读入后编码! "< system("pause"); return; } if(text.num==0){ cout<<"正文不存在,请输入或读入正文后编码! "< system("pause"); return; } charcode[26*N]={0}; for(inti=0;i for(intj=1;j<=HT.num;j++){ if(text.content[i]==HT.alphabet[j]) break; } if(j>HT.num){ cout<<"编码出错! "< system("pause"); return; } else strcat(code,HT.HC[j]); } CodeMalloc(c,strlen(code)); strcpy(c.bin,code); cout<<"编码结果为: "< cout<<"编码结果将保存到文件..."< if(CodeSave(c)) cout<<"保存成功! "< else cout<<"保存失败! "< system("pause"); } 正文解码: voiddecode(HuffmantreeHT){//解码 system("cls"); cout<<"--------------------------------\n"; cout<<"读取文件译码\n"; cout<<"--------------------------------\n"; if(HT.num==0){ cout<<"哈夫曼树不存在,请初始化或读入后编码! "< return; } Codeco; intflag,i,j,k; char*s; chartemptext[N+1]; inttextindex=0; cout<<"将从文件中读取编码..."< CodeInit(co); if(CodeRead(co)){ co.bin[co.num]=0; cout<<"读取内容为: "< cout<<"读取成功! "< } else{ cout<<"读取失败! 返回! "< return; } for(i=0;i for(j=i;j flag=0; s=substring(co,i,j); for(k=1;k<=HT.num;k++) if(strcmp(s,HT.HC[k])==0){ flag=1; temptext[textindex++]=HT.alphabet[k]; break; } if(flag) break; } } if(j==co.num&&k>HT.num){ cout<<"解码出错! "< system("pause"); return; } temptext[textindex]=0; cout<<"译码结果为: "< cout<<"是否保存译码结果到文件? "; if(istrue()){ Texttext; TextInit(text); text.num=strlen(temptext); TextMalloc(text,text.num); strcpy(text.content,temptext); if(TextSave(text)) cout<<"保存成功! "< else cout<<"保存失败! "< } else cout<<"返回上级菜单! "< } 凹入法印哈夫曼树: voidtreeprinting(HuffmantreeHT,intindex,intlevel,char*filename,intflag){//凹入打印哈夫曼树 if(index<1||index>2*HT.num-1) return; ofstreamoutfile(filename,ios: : app); for(inti=0;i if(flag) outfile<<""; cout<<""; } if(index<=HT.num){ if(HT.alphabet[index]==''){ if(flag) outfile<<"blank"< cout<<"blank"< } else{ cout< outfile< } } else{ if(flag) outfile<<(int)HT.hftree[index].weight< cout<<(int)HT.hftree[index].weight< } if(HT.hftree[index].rchild) treeprinting(HT,HT.hftree[index].rchild,level+1,filename,1);//左右子树深度相同 if(HT.hftree[index].lchild) treeprinting(HT,HT.hftree[index].lchild,level+1,filename,1); if(flag) outfile.close(); } 3.3调试分析 测试数据及测试结果在7中有详细给出,这里省略。 算法分析: 编码函数中,每次都要将待编码字符与正文字符比较,相当于顺序表查找,哈夫曼树中有n个字符,时间复杂度为O(n^2)。 解码函数中,每次从编码中取出一定长的子串与哈夫曼编码比较,逐渐增加子串长度,直到找到相同子串,得到解码后的字符。 用凹入法打印哈夫曼树,先输出最顶端的结点,然后根据包含关系,将子树的结点缩进一定长度,用递归调用实现该打印。 调试中遇到的问题及解决方法: 1.空格的输入。 在C++中用cin输入,空格作为截止符,无法正常输入,于是改成了C语言的scanf函数,接收空格。 2.空格的读入和保存。 在C++中用outfile<<和infile>>的方式读入或保存空格,功能类似于cin中的功能,即作为输入输出的截止符。 无法正常保存和读出。 于是用二进制读入读出字符,但这样存在一个弊端: 直接打开保存的文件将无法直接查看其中的内容,解决方法还有待改善。 3.当同一个函数中同时存在puts与cout时,输出会出错。 于是一个函数中要么用C语言的输入输出和puts,要么只有cout函数。 3.4用户手册 1本程序执行文件为huffmancoding.exe。 2用户进入系统后可输入相应数字选择菜单,本系统可实现哈夫曼树的建立,以及利用哈夫曼编码对字符进行编码、解码的功能、哈夫曼树的凹入法打印功能。 3运行期间产生的哈夫曼树建立、字符编码、字符解码、哈夫曼树打印等中间结果均可保存在文件。 4总结 1.关于哈夫曼编码的思考: 哈夫曼编码冗余度很低,充分地缩小了存储正文所需的存储空间,方便传输。 但从本次实验来看,哈夫曼编码在解码时由于不知道到底多长截取为一段来解码成字符,需要一点一点地试。 这次实验是从最小1比特截为一段,后面逐渐增加截取长度,直到这个字符解码成功。 还可以优化一点,先根据哈夫曼编码的最短长度,以最短长度截取一段,然后逐渐增加,以降低运行耗时。 2.关于调试过程中的感受: 在以往的实验中,大都是用C语言完成实验,而这次为了使保存的文件不是乱码,用了C++.但因为空格的问题,直接保存有一定的问题,最终还是用了二进制的方式保存,使程序能够正常运行。 主要可能是因为对文件的使用方式不太熟悉,以后还有待提高。 除此之外,这次因为马虎给自己添了不少麻烦,浪费了很多时间,是一次小小的教训。 5、程序清单: (见附录) 7、程序运行结果 主界面 初始化: 编码: 1.从文件读入哈夫曼树 2.直接输入正文 3.从文件读入正文 4.正文编码 译码: 2.正文译码 印代码文件: 凹入法印哈夫曼树 附录1 #include #include #include #include #include #defineElemtypedouble #defineBINchar #defineN500 #defineN2100 #defineTree1//1表示树 #defineBeTran2//2表示正文 #defineCoFile3//3表示编码后结果 structHTNode{//哈夫曼树的结点 Elemtypeweight; intparent,lchild,rchild; }; structHuffmantree{//哈夫曼树 intnum; char*alphabet; HTNode*hftree; int*HCnum; BIN**HC; }; structText{//正文 intnum; char*content; }; structCode{//编码,用字符型数字表示 intnum; BIN*bin; }; voidHufftreeInit(Huffmantree&H){//对结构体Huffmantree初始化 H.num=0; H.alphabet=NULL; H.hftree=NULL; H.hftree=NULL; } voidHufftreeMalloc(Huffmantree&H,intnum){//给结构体Huffmantree分配空间 H.num=num; H.alphabet=(char*)malloc((H.num+1)*sizeof(char)); H.hftree=(HTNode*)malloc(2*H.num*sizeof(HTNode)); H.HC=(char**)malloc((H.num+1)*sizeof(char*)); H.HCnum=(int*)malloc((H.num+1)*sizeof(int)); for(inti=1;i<=2*num-1;i++){ H.hftree[i].lchild=0; H.hftree[i].parent=0; H.hftree[i].rchild=0; H.hftree[i].weight=0; } } voidTextInit(Text&c){//结构体Text初始化 c.num=0; c.content=NULL; } voidTextMalloc(Text&c,intnum){//给结构体Text分配存储空间 c.num=num; c.content=(char*)malloc(sizeof(char)*(c.num+1)); } voidCodeInit(Code&co){//给结构体code分配存储空间 co.num=0; co.bin=NULL; } voidCodeMalloc(Code&co,intnum){//给结构体code分配存储空间 co.num=num; co.bin=(BIN*)malloc((co.num+1)*sizeof(BIN)); }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 哈夫曼 编码 译码 系统