1、 20180820 一、需求分析 1、问题描述 利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(解码)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站设计一个哈夫曼编译码系统。 2、基本要求 (1)初始化(Initialzation)。从数据文件DataFile.txt中读入字符及每个字符的权值,建立哈夫曼树HuffTree; (2)编码(EnCoding)。用已建好的哈夫曼树,对文件To
2、BeTran.txt中的文本进行编码形成报文,将报文写在文件Code.txt中; (3)译码(Decoding)。利用已建好的哈夫曼树,对文件CodeFile.txt中的代码进行解码形成原文,结果存入文件Textfile.txt中; (4)输出(Output)。输出DataFile.txt中出现的字符以及各字符出现的频度(或概率);输出ToBeTran.txt及其报文Code.txt;输出CodeFile.txt及其原文Textfile.txt; 二、概要设计 1.数据结构 本程序需要用到以一个结构体HTNode,以及一个二维数组HuffmanCode。 2.程序模块 本程序
3、包含两个模块,一个是实现功能的函数的模块,另一个是主函数模块。 系统子程序及功能设计 本系统共有七个子程序,分别是: a.int min1(HuffmanTree t,int i)//进行比较 b.void select(HuffmanTree t,int i,int *s1,int *s2)// 求权值最小的两个数 c.void HuffmanCoding(HuffmanTree *HT,HuffmanCode *HC,int *w,char *u,int n)// /* w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC */ d.void In
4、itialzation(HuffmanTree *HT,HuffmanCode *HC)//初始化 e.int EnCoding(HuffmanTree *HT,HuffmanCode *HC)//对文件ToBeTran.txt中的文本进行编码形成报文,将报文写在文件Code.txt中 f.int pipei(char *c,int n,HuffmanCode *HC)//在huffmancode寻找匹配的编码 g.void Decoding(HuffmanTree *HT,HuffmanCode *HC)//对文件CodeFile.txt中的代码进行解码形成原文,结果存入文件Textf
5、ile.txt中 3. 各模块之间的调用关系以及算法设计 主函数调用Initialzation,EnCoding,Decoding。 函数HuffmanCoding调用函数select。 函数select调用函数min1 函数Initialzation调用函数HuffmanCoding 函数Decoding调用函数pipei 三、详细设计 1.数据类型定义 typedef struct { unsigned int weight; unsigned int parent,lchild,rchild; char ch; }HTNode,*
6、HuffmanTree; /* 动态分配数组存储赫夫曼树 */ typedef char **HuffmanCode; /* 动态分配数组存储赫夫曼编码表 */ 2.系统主要子程序详细设计 a. 构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC void HuffmanCoding(HuffmanTree *HT,HuffmanCode *HC,int *w,char *u,int n) /* 算法6.12 */ { /* w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC */ int m,i,s1,s2,start; unsig
7、ned c,f; HuffmanTree p; 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,++u) { (*p).ch=*u; (*p).weight=*w; (*p).parent=0; (*p).lchild=0; (*p).rchild=0; }
8、 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].w
9、eight+(*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; /* 编码结束符位置 *
10、/ 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]); /*
11、从cd复制编码(串)到HC */ } free(cd); /* 释放工作空间 */ } b.初始化 void Initialzation(HuffmanTree *HT,HuffmanCode *HC)//初始化 { FILE *f1; int i,n=0; if((f1=fopen("DataFile.txt","r"))==NULL) { printf("error\n"); } int g[100]; char h[100]; printf("从数据文件DataFile.txt中
12、读入字符及每个字符的权值\n"); for(i=1;;i++) { fscanf(f1,"%c",&h[i]); if(h[i]=='#') break; fscanf(f1,"%d",&g[i]); n++; printf("%c: ",h[i]); printf("%d\n",g[i]); } fclose(f1); HuffmanCoding(HT,HC,g,h,n); } c.编码 int EnCodin
13、g(HuffmanTree *HT,HuffmanCode *HC)//对文件ToBeTran.txt中的文本进行编码形成报文,将报文写在文件Code.txt中 { int i,j,m=0,n=0; FILE *f1,*f2,*f3; if((f1=fopen("DataFile.txt","r"))==NULL) { printf("error\n"); } int g[100]; char h[100]; for(i=1;;i++) { fscanf(f1,"%c",&h[i]);
14、 if(h[i]=='#') break; fscanf(f1,"%d",&g[i]); n++; } fclose(f1); if((f2=fopen("ToBeTran.txt","r"))==NULL) { printf("error\n"); } printf("从数据文件ToBeTran.txt中读入字符\n"); char u[100],a[100]; for(i=1;;i++) { fscanf(f2,"%c",






