数据结构课程设计指导教师:吴小平学院:信息科学与技术学院班级:软件三班学号:201313040314姓名:孙召阳目录一、前言1.摘要二、实验目的三、题目--赫夫曼编码/译码器1.问题描述2.基本要求3.测试要求4.实现提示四、需求分析--具体要求前言1.摘要随着计算机的普遍应用与日益发展,其应用早已不局限于简单的数值运算,而涉及到问题的分析、数据结构框架的设计以及设计最短路线等复杂的非数值处理和操作。
算法与数据结构的学习就是为以后利用计算机资源高效地开发非数值处理的计算机程序打下坚实的理论、方法和技术基础。
算法与数据结构旨在分析研究计算机加工的数据对象的特性,以便选择适当的数据结构和存储结构,从而使建立在其上的解决问题的算法达到最优。
数据结构是在整个计算机科学与技术领域上广泛被使用的术语。
它用来反映一个数据的内部构成,即一个数据由那些成分数据构成,以什么方式构成,呈什么结构。
数据结构有逻辑上的数据结构和物理上的数据结构之分。
逻辑上的数据结构反映成分数据之间的逻辑关系,而物理上的数据结构反映成分数据在计算机内部的存储安排。
数据结构是数据存在的形式。
二、实验目的学习数据结构是为了将实际问题中所涉及的对象在计算机中表示出来并对它们进行处理。
通过课程设计可以提高学生的思维能力,促进学生的综合应用能力和专业素质的提高。
通过此次课程设计主要达到以下目的:1.了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;2.初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;3.提高综合运用所学的理论知识和方法独立分析和解决问题的能力;4.训练用系统的观点和软件开发一般规范进行软件开发,培养软件工作者所应具备的科学的工作方法和作风。
三、题目--赫夫曼编码/译码器1. 问题描述利用赫夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站编写一个赫夫曼码的编/译码系统。
2.基本要求一个完整的系统应具有以下功能:(1) I:初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立赫夫曼树,并将它存于文件hfmTree中。
(2) E:编码(Encoding)。
利用已建好的赫夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3) D:译码(Decoding)。
利用已建好的赫夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。
3.测试要求(1) 已知某系统在通信联络中只可能出现八种字符,其频率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计赫夫曼编码。
(2) 用下表给出的字符集和频度的实际统计数据建立赫夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FA VORITE”。
字符 A B C D E F G H I J K L M频度186 64 13 22 32 103 21 15 47 57 1 5 32 20字符N O P Q R S T U V W X Y Z频度57 63 15 1 48 51 80 23 8 18 1 16 1四、概要设计1)问题分析哈夫曼树的定义1.哈夫曼树节点的数据类型定义为:typedef struct{ //赫夫曼树的结构体char ch;int weight; //权值int parent,lchild,rchild;}htnode,*hfmtree;2)所实现的功能函数如下1、void hfmcoding(hfmtree &HT,hfmcode &HC,int n)初始化哈夫曼树,处理InputHuffman(Huffman Hfm)函数得到的数据,按照哈夫曼规则建立2叉树。
此函数块调用了Select()函数。
2、void Select(hfmtree &HT,int a,int *p1,int *p2) //Select函数,选出HT树到a为止,权值最小且parent为0的2个节点2、int main()主函数:利用已建好的哈夫曼树(如不在内存,则从文件hfmtree.txt中读入)对文件中的正文进行编码,然后将结果存入文件codefile.txt中。
如果正文中没有要编码的字符,则键盘读入并存储到ToBeTran文件中。
读入ToBeTran中将要编码的内容,将编码好的哈夫曼编码存储到CodeFile中。
3、Encoding编码功能:对输入字符进行编码4、Decoding译码功能:利用已建好的哈夫曼树将文件codefile.txt中的代码进行译码,结果存入文件textfile.dat 中。
Print() 打印功能函数:输出哈夫曼树,字符,权值,以及它对应的编码。
5.主函数的简要说明,主函数主要设计的是一个分支语句,让用户挑选所实现的功能。
使用链树存储,然后分别调用统计频数函数,排序函数,建立哈夫曼函数,编码函数,译码函数来实现功能。
2)系统结构图(功能模块图)五.程序说明1).哈夫曼编码/译码器源代码#include<iostream.h>#include<stdio.h>#include<stdlib.h>#include<string.h>#include<fstream.h>typedef struct{ //赫夫曼树的结构体char ch;int weight; //权值int parent,lchild,rchild;}htnode,*hfmtree;typedef char **hfmcode;void Select(hfmtree &HT,int a,int *p1,int *p2) //Select函数,选出HT树到a为止,权值最小且parent为0的2个节点{int i,j,x,y;for(j=1;j<=a;++j){if(HT[j].parent==0){x=j;break;}}for(i=j+1;i<=a;++i){if(HT[i].weight<HT[x].weight&&HT[i].parent==0){x=i; //选出最小的节点}}for(j=1;j<=a;++j) {if(HT[j].parent==0&&x!=j){y=j;break;}}for(i=j+1;i<=a;++i){if(HT[i].weight<HT[y].weight&&HT[i].parent==0&&x!=i){y=i; //选出次小的节点}}if(x>y){*p1=y;*p2=x;}else{*p1=x;*p2=y;}}void hfmcoding(hfmtree &HT,hfmcode &HC,int n) //构建赫夫曼树HT,并求出n个字符的赫夫曼编码HC {int i,start,c,f,m,w;int p1,p2;char *cd,z;if(n<=1){return;}m=2*n-1;HT=(hfmtree)malloc((m+1)*sizeof(htnode));for(i=1;i<=n;++i) //初始化n个叶子结点{printf("请输入第%d字符信息和权值:",i);scanf("%c%d",&z,&w);while(getchar()!='\n'){continue;}HT[i].ch=z;HT[i].weight=w;HT[i].parent=0;HT[i].lchild=0;HT[i].rchild=0;}for(;i<=m;++i) //初始化其余的结点{HT[i].ch='0';HT[i].weight=0;HT[i].parent=0;HT[i].lchild=0;HT[i].rchild=0;}for(i=n+1;i<=m;++i) //建立赫夫曼树{Select(HT,i-1,&p1,&p2);HT[p1].parent=i;HT[p2].parent=i;HT[i].lchild=p1;HT[i].rchild=p2;HT[i].weight=HT[p1].weight+HT[p2].weight;}HC=(hfmcode)malloc((n+1)*sizeof(char *));cd=(char *)malloc(n*sizeof(char));cd[n-1]='\0';for(i=1;i<=n;++i) //给n个字符编码{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);}int main(){char code[100],h[100],hl[100];int n,i,j,k,l;ifstream input_file; //文件输入输出流ofstream output_file;char choice,str[100];hfmtree HT;hfmcode HC;cout<<"\n";cout<<" "<<"计算机(3)班"<<" "<<"Q07620307"<<" "<<"XXX\n";while(choice!='Q'&&choice!='q') //当choice的值不为q且不为Q时循环{cout<<" "<<"*************************赫夫曼编码/译码器*************************\n";cout<<" "<<"I.Init"<<" "<<"E.Encoding"<<""<<"D.Decoding"<<" "<<"Q.Exit\n";cout<<"请输入您要操作的步骤:";cin>>choice;if(choice=='I'||choice=='i') //初始化赫夫曼树{cout<<"请输入字符个数:";cin>>n;hfmcoding(HT,HC,n);for(i=1;i<=n;++i){cout<<HT[i].ch<<":"<<HC[i]<<endl;}output_file.open("hfmTree.txt");if(!output_file){cout<<"can't oen file!"<<endl;return 1;}for(i=1;i<=n;i++){output_file<<"("<<HT[i].ch<<HC[i]<<")";}output_file.close();cout<<"赫夫曼树已经创建完毕,并且已经放入hfmTree.txt文件中!"<<endl;}else if(choice=='E'||choice=='e') //进行编码,并将字符放入ToBeTran.txt,码值放入CodeFile.txt中{printf("请输入字符:");gets(str);output_file.open("ToBeTran.txt");if(!output_file){cout<<"can't oen file!"<<endl;return 1;}output_file<<str<<endl;output_file.close();output_file.open("CodeFile.txt");if(!output_file){cout<<"can't oen file!"<<endl;return 1;}for(i=0;i<strlen(str);i++){for(j=0;j<=n;++j){if(HT[j].ch==str[i]){output_file<<HC[j];break;}}}output_file.close();cout<<"\n";cout<<"编码完毕,并且已经存入CodeFile.txt文件!\n";input_file.open("CodeFile.txt"); //从CodeFile.txt中读入编码,输出在终端if(!input_file){cout<<"can't oen file!"<<endl;return 1;}input_file>>code;cout<<"编码码值为:"<<code<<endl;input_file.close();}else if(choice=='D'||choice=='d') //读入CodeFile.txt中的编码进行译码,将译出来的字符放入Textfile.txt中{input_file.open("CodeFile.txt");if(!input_file){cout<<"can't oen file!"<<endl;return 1;}input_file>>h;input_file.close();output_file.open("Textfile.txt");if(!output_file){cout<<"can't oen file!"<<endl;return 1;}k=0;while(h[k]!='\0') //先用编码中的前几个和字符的编码相比较,然后往后移{for(i=1;i<=n;i++){l=k;for(j=0;j<strlen(HC[i]);j++,l++){hl[j]=h[l];}hl[j]='\0';if(strcmp(HC[i],hl)==0){output_file<<HT[i].ch;k=k+strlen(HC[i]);break;}}}output_file.close();input_file.open("Textfile.txt");if(!input_file){cout<<"can't oen file!"<<endl;return 1;}input_file>>h;cout<<h<<endl;input_file.close();cout<<"译码结束,字符已经存入Textfile.txt文件中!"<<endl;}else if(choice=='Q'||choice=='q') //退出程序{exit(0);}else //如果选了选项之外的就让用户重新选择{cout<<"您没有输入正确的步骤,请重新输入!"<<endl;}cout<<endl;}return 0;}六.调试分析编码、译码、退出七.实验心得与体会在我自己课程设计中,就在编写好源代码后的调试中出现了不少的错误,遇到了很多麻烦及困难,我的调试及其中的错误和我最终找出错误,修改为正确的能够执行的程序中,通过分析,我学到了:在定义头文件时可多不可少,即我们可多写些头文件,肯定不会出错,但是若没有定义所引用的相关头文件,必定调试不通过;在执行译码操作时,不知什么原因,总是不能把要编译的二进制数与编译成的字符用连接号连接起来,而是按顺序直接放在一起,视觉效果不是很好。