一、需求分析1.运行环境:Microsoft Visual C++2.程序所实现的功能:初始化:输入一串字符(正文),计算不同字符(包括空格)的数目以及每种字符出现的频率(以该种字符出现的次数作为其出现频率),根据权值建立哈夫曼树,输出每一种字符的哈夫曼编码。
编码:利用求出的哈夫曼编码,对该正文(字符串)进行编码,并输出。
译码:对于得到的一串编码,利用已求得的哈夫曼编码进行译码,将译出的正文输出。
输出哈夫曼树形态:以树的形式输出哈夫曼树。
3.程序的输入,包含输入的数据格式和说明:there are three students(char型)4.程序的输出,程序输出的形式:②统计字符出现次数并输出③根据字符出现次数求出哈夫曼编码并输出(根据算法差异得到的编码可能不同,但应具有两个特征,一是编码长度应与表中相同,二是编码应该是前缀编码)④以树的形式输出哈夫曼树二、设计说明1. 算法设计的思想1) 确定哈夫曼树和哈夫曼编码的储存表示2)在HT[1..n]中选择parent为0的且weight最小的两个节点s1和s23)w存放n个字符的权值(均>0),构造哈夫曼树HT,输出静态链表(数组)储存哈夫曼树储存结构模拟,然后求出n个字符的哈夫曼编码HC4)利用哈夫曼编码对密文进行译码,输出译后的字符串5) 在main()中实现:输入一串字符(正文),计算不同字符(包括空格)的数目以及每种字符出现的频率(以该种字符出现的次数作为其出现频率,然后调用各子函数实现该程序功能2.主要的数据结构设计说明Select(HuffmanTree &HT, int n, int &s1, int &s2){//在HT[1..n]中选择parent为0且weight最小的两个结点,// 其序号分别为s1和s2。
HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n){ // w存放n个字符的权值(均>0),构造哈夫曼树HT,// 并求出n个字符的哈夫曼编码HCfor (i=n+1; i<=m; i++) { // 建哈夫曼树// 在HT[1..i-1]中选择parent为0且weight最小的两个结点,// 其序号分别为s1和s2。
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;HuffmanTran(HuffmanTree &HT,char* &str1,char* &str2,int n){//利用哈夫曼编码对密文进行译码,输出译后的字符串3.程序的主要流程图4.程序的主要模块,要求对主要流程图中出现的模块进行说明1)初始化:①输入正文:输入一串字符(正文)②统计字符出现次数并输出:计算不同字符(包括空格)的数目以及每种字符出现的频率(以该种字符出现的次数作为其出现频率)③求出哈夫曼编码并输出④以树的形式输出哈夫曼树2)编码:发送方利用得到的哈夫曼编码对正文进行编码,输出密文3)译码:接收方利用哈夫曼编码对密文进行译码,输出译后的字符串5.程序的主要函数及其伪代码说明Select(HuffmanTree &HT, int n, int &s1, int &s2)//在HT[1..n]中选择parent为0且weight最小的两个结点,// 其序号分别为s1和s2。
HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n) {// w存放n个字符的权值(均>0),构造哈夫曼树HT,// 并求出n个字符的哈夫曼编码HCfor (i=n+1; i<=m; i++) { // 建哈夫曼树// 在HT[1..i-1]中选择parent为0且weight最小的两个结点,// 其序号分别为s1和s2。
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;HuffmanTran(HuffmanTree &HT,char* &str1,char* &str2,int n){//利用哈夫曼编码对密文进行译码,输出译后的字符串三、上机结果及体会1.实际完成的情况说明:初始化:输入一串字符(正文),计算不同字符(包括空格)的数目以及每种字符出现的频率(以该种字符出现的次数作为其出现频率),根据权值建立哈夫曼树,输出每一种字符的哈夫曼编码。
编码:利用求出的哈夫曼编码,对该正文(字符串)进行编码,并输出。
译码:对于得到的一串编码,利用已求得的哈夫曼编码进行译码,将译出的正文输出。
输出哈夫曼树形态:以树的形式输出哈夫曼树。
2. 程序的性能分析,包括时空分析程序相对比较复杂,以四维数组为哈弗曼树的存储结构3.打印程序运行时的初值和运行结果,画出相应的图示译码:4.上机过程中出现的问题及其解决方案1)问题:统计字符出现次数并输出;解决方案:运用swicth函数和数组来实现该功能2)问题:输出哈弗曼树;解决方案:运用静态链表(数组)进行哈夫曼树储存结构模拟5. 程序中可以改进的地方说明1)统计字符出现次数并输出,本程序只能输入there are three students来运行,该处可以运用其他函数或方法进行改进2)译码处存在问题,可以进一步改进6. 程序中可以扩充的功能及设计实现假想1)进行更多的输入的编码和译码,使程序更具实用性2)多应用一些C++知识,使程序更加简洁一些7.收获及体会:通过这次课题实验的程序实践,我实在获益匪浅!数据结构是这个学期开展的一门学科,学习好这门学科是非常重要的,在以后的程序设计方面这门学科能给我们很大的帮助。
同时,学习这门学科也是艰辛的,因为它比较难懂,这不仅需要我们要发挥我们的聪明才志,还需要我们在不断的实践中领悟。
这次的程序设计对我来说无疑是一个具大的考验,从接起课题后,我就一直为实现程序而努力,翻阅相关书籍、在网上查找资料。
因为开始时基础不是很好,过程中遇到了不少的阻碍,编写程序的进度也比较慢。
虽然如此,但是通过自己的努力与老师的指导及同学的帮助,我对这次实验的原理有了一定的理解,通过参照从网上找到的源程序,终于在其它源程序的基础下写出了本次实验的核心算法,并使其能够正常的运行。
这将近两个星期的设计工作,让我体会到了作为一个编程人员的艰难,一个算法到具体实现,再到应用层面的开发是需要有一段较长的路要走的,不是一朝一夕就可以实现的,而且在编好程序后,编程人员还要花很多的时间去完善它,其中包含的心酸,外人是不会明白的。
非常感谢在背后一直给我指导的老师和同学,他们的支持和鼓励让我在遇到挫折时能够站起来战胜它,也让我走到了今天这一步,完成了实验的设计。
今后,我会更加努力的学习专业知识,提高自我的能力。
8.源程序:见附录四、调试分析五、参考文献1.数据结构(C语言版) 147页——赫夫曼树和赫夫曼树编码的存储表示,及求赫夫曼编码的算法2.C语言设计(第三版) 371页—377页附录E C库函数——用于程序的开始3.网络——赫夫曼译码六、附录程序清单:Honor Code:#include <stdio.h>#include <stdlib.h>#include <string.h>//--------哈夫曼树和哈夫曼编码的储存表示--------typedef struct {int weight;int parent,lchild,rchild;}HTNode,*HuffmanTree; //动态分配数组储存哈夫曼树typedef char ** HuffmanCode; //动态分配数组储存哈夫曼编码表//-------------在HT[1..n]中选择parent为0的且weight最小的两个节点s1和s2---------void Select(HuffmanTree HT,int n,int & s1,int &s2){for(int i=1;i<=n;i++) //任取两个parent为0的节点赋值给s1和s2if(!HT[i].parent){s1=i; break;}for(i++;i<=n;i++)if(!HT[i].parent){s2=i; break;}if(HT[s1].weight-HT[s2].weight){int temp; temp=s1; s1=s2; s2=temp;}for(i=1;i<=n;i++) //对数组进行遍历,寻找最小的两个节点 if(!HT[i].parent){if(HT[i].weight<HT[s1].weight){s2=s1; s1=i;}elseif(HT[i].weight<HT[s2].weight&&i!=s1)s2=i;}}//---------w存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC----------void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n){if(n<=1)return;int s1,s2,i,num=2*n-1;HuffmanTree p;HT=(HuffmanTree)malloc((num+1)*sizeof(HTNode)); //0号单元未用for(p=HT+1,i=1;i<=n;i++,p++,w++){//对静态链表初赋值p->weight=*w; p->lchild=NULL; p->parent=NULL; p->rchild=NULL;}for(;i<=num;p++,i++){p->weight=0; p->lchild=NULL; p->parent=NULL; p->rchild=NULL;}for(i=n+1;i<=num;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 *));//分配n个字符编码的头指针向量char * temp=(char *)malloc(n*sizeof(char));//分配求编码的工作空间temp[n-1]='\0'; //编码结束符for(i=1;i<=n;i++){ //逐个字符求哈夫曼编码int start=n-1; //编码结束符位置for(int f=HT[i].parent,h=i;f;h=f,f=HT[f].parent)//从叶子到根逆向求编码if(HT[f].lchild==h)temp[--start]='0';elsetemp[--start]='1';HC[i]=(char *)malloc((n-start)*sizeof(char));//为第i个字符编码分配空间strcpy(HC[i],&temp[start]);//懂temp复制字符串到HC[i]}free(temp); //释放工作空间}//-------输出静态链表(数组)储存哈夫曼树储存结构模拟------void print(HuffmanTree HT,int n){int m=n*2-1;printf("静态链表(数组)储存哈夫曼树储存结构模拟:\nHT weightparent lchild rchild\n");for(int i=1;i<=m;i++)printf("%2d%7d%8d%8d%8d\n",i,HT[i].weight,HT[i].parent,HT[i].lchild,H T[i].rchild);}//------利用哈夫曼编码对密文进行译码,输出译后的字符串--------void HuffmanTran(HuffmanTree &HT,char* &str1,char* &str2,int n){//HT为Huffman树,str1为存放编码的数组,str2为存放译码的数组HuffmanTree p=HT+2*n-1;char* q=str1;int i=0,l,j=0;l=strlen(str1);printf("%d%c",l,'\n');str2=(char*)malloc(l*sizeof(char));for(i=0;i<l;++i){printf("%c%c",*p,'\n');if(str1[i]=='0') p=HT+p->lchild;else if(str1[i]=='1') p=HT+p->rchild;if(p->lchild==0&&p->rchild==0){str2[j]=p->name;p=HT+2*n-1;j++;}q++;}str2[j]='\0';printf("%d%c",j,'\n');}//---------主函数-------------int main(){char x;int i,j;auto w[10]={0};while((x=getchar())!='\n'){//统计字符出现次数并输出switch(x){case 'a':++w[0];break;case 'd':++w[1];break;case 'e':++w[2];break;case 'h':++w[3];break;case 'n':++w[4];break;case 'r':++w[5];break;case 's':++w[6];break;case 't':++w[7];break;case 'u':++w[8];break;case ' ':++w[9];break;}}for(i=0;i<10;i++){printf("%d\n",w[i]);}HuffmanTree HT;HuffmanCode HC;HuffmanCoding(HT,HC,w,10);print(HT,10);for(i=1;i<=10;i++)printf("叶子%d的编码为:%s\n",w[i-1],HC[i]);return 0;char* str1,*str2;str1=(char*)malloc(80*sizeof(char));printf("请输入用于解码的0、1序列:\n");printf("0、1序列串:");scanf("%s",str1);str2=(char*)malloc(40*sizeof(char)); //Huffman译码及输出HuffmanTran(HT,str1,str2,10);printf("哈弗曼编码-----相应字符\n");for(i=0;i<strlen(str2);++i)printf("%c",str2[i]);printf("%c",'\n');}11。