赫夫曼编译码器说明书.docx
- 文档编号:28848263
- 上传时间:2023-07-20
- 格式:DOCX
- 页数:31
- 大小:185.10KB
赫夫曼编译码器说明书.docx
《赫夫曼编译码器说明书.docx》由会员分享,可在线阅读,更多相关《赫夫曼编译码器说明书.docx(31页珍藏版)》请在冰豆网上搜索。
赫夫曼编译码器说明书
目录
摘要1
前言2
正文3
1.采用类c语言定义相关的数据类型3
2.各模块的伪码算法3
3.函数的调用关系图3
4.调试分析3
5.测试结果3
6.源程序(带注释)3
总结4
参考文献5
致谢6
附件Ⅰ部分源程序代码7
摘要
本课程设计主要研究如何解决对于给定的叶子数目及其权值构造最优二叉树的方法。
通过对问题的分析,采用哈夫曼算法的设计思想。
根据给定的权值构成二叉树森林,在森林中任意选取两棵根结点权值最小的树,将这两棵树合并为新的树,为保证新树仍为二叉树,需要增加一个新的结点作为根将这两个孩子的权值之和作为新树根的权值。
对新的森林重复上述步骤直到森林中只剩一棵树为止。
此树即为哈夫曼树。
前言
字符以某种编码形式存储在计算机中,目前世界上应用最广泛的两个字符是ASCII码(美国信息交换标准码)和EBCDIC码(扩充的二进制的十进制信息码)。
当采纳这两个字符集时字符在计算机内是以固定长度的比特串表示的。
但事实上,在具体应用中字符集中字符的使用频率常常差别很大,为了提高存储和传输的效率,可采用不等长的编码方式。
若要设计不等长编码,则要求对字符集中任一字符的编码都不是另一个字符编码的前缀,称这种编码符合前缀特性,也称前缀编码,前缀编码可以一个字符一个字符地进行译码,不需要在字符之间添加分隔符。
利用哈夫曼编码可以解决上述问题。
正文
1.采用类c语言定义相关的数据类型
用C语言实现:
typedefstructHaffmanTreeNode
{
charch,code[15];//ch代表当前字符,code[]代表这个字符的编码
intweight;//当前统计的字符的个数
intparent,lchild,rchild;
}HTNode,*HaTree;
typedefstruct
{HTNodearr[MAX_NODE];
inttotal;
}HTree;
Max_Node代表数的最大结点数
Max_Weight代表权值的最大值
typedefstruct//结点类型
{
intweight;//根节点的权值
intflag;//标志位,为0即没有双亲,反之则是
intparent;//双亲结点
charch;//要编码的字符,即哈夫曼树叶子
intlchild;//根节点的左孩子
intrchild;//根节点的右孩子
}HafNode;
typedefstruct//哈夫曼编码
{
intbit[MAX_NODE];//二进制编码位,用于存放哈夫曼树编码
intstart;//编码的值在数组存放的起始位置
intweight;//要编码的字符出现的频率,即权值
charch;//要编码的字符
}Code;
typedefstruct//编码操作类型
{
charbit[MAX_NODE];//将字符的编码结果存入bit数组中
charch;//要编码的字符
intweight;//字符出现的频率
}Coding;
typedefstruct//输入字符信息
{HafNodearr[MAX_NODE];//数组结点信息
inttotal;//统计输入字符的种类个数
}HTree;
2.各模块的伪码算法
算法描述:
intstatistic_char(char*text,HTree*t)/*统计字符出现的频率*/
{
inttext_len=strlen(text);
t->total=0;
for(i=0;i { for(j=0;j if(t->arr[j].ch==text[i]) {......统计已经出现的字符的个数 } if(j==t->total) {......记录新出现的字符 } } returnt->total;//打印出字符和它们的出现的次数 } intcreate_htree(HTree*t)/*建立一棵赫夫曼树,并对数据初始化*/ { for(i=0;i {........把每一个结点都建立成一棵只包含它自己的树 } while(t->total { min1=min2=Max_Weight; for(i=0;i {.......找到当前权值最小的两个结点,并把它们建立成一棵新树,其中树根的权值为这两个的权值的和 } t->total++; } return0; } voidcoding(HTree*t,inthead_i,char*code)/*对哈夫曼树进行编码*/ { if(head_i==-1)//判断是否为空,为空返回 return; ......从树的根节点出发,查找左子树输出0,查找右子树输出1,直到找到该树的叶子结点,按每个叶子结点在数组中的下标依次输出 } voidprint_htree_ldr(HTree*t,inthead_i,intdeep,int*path)/*中序打印树*/ {........ 判断是否为空树,是的话返回;不是的话,按照先输出左孩子,然后输出双亲,再输出右孩子的方法依次打印各个字符和它的权值; } voidcode_string(char*text,HTree*t)/*对字符进行编码*/ {变量初始化: for(条件判断) { 依次输出每个字符的编码 } } 3.函数的调用关系图 4.调试分析 a、调试中遇到的问题及对问题的解决方法 调试过程中遇到的问题及解决: 我在该程序中遇到的最大问题是如何以文件形式存储赫夫曼树,以及如何从文件读取赫夫曼树,读与存都要涉及到字符串转换成整数或整数转换成字符串的问题,最后终于成功了,可是很耗时,不知道是不是我的方法太不好了。 b、算法的时间复杂度和空间复杂度 算法的时空分析 在此程序中,存储字符串都用了指针,先动态申请空间,然后再存,这样就有效的利用了空间,不过为了实现任意长字符串的输入,最后转存到字符指针里,这样就浪费了一些空间。 而对于哈夫曼树算法本身,由于这里只是一个静态的,所以当进行网络传输时,可能会显得效率比较低。 5.测试结果 6.源程序(带注释) #include #include #include #defineMAX_NODE100//代表哈夫曼树最大的结点数 #defineMAX_VALUE10000//代表权值的最大值 typedefstruct//结点类型 { intweight;//根节点的权值 intflag;//标志位,为0即没有双亲,反之则是 intparent;//双亲结点 charch;//要编码的字符,即哈夫曼树叶子 intlchild;//根节点的左孩子 intrchild;//根节点的右孩子 }HafNode; typedefstruct//哈夫曼编码 { intbit[MAX_NODE];//二进制编码位,用于存放哈夫曼树编码 intstart;//编码的值在数组存放的起始位置 intweight;//要编码的字符出现的频率,即权值 charch;//要编码的字符 }Code; typedefstruct//编码操作类型 { charbit[MAX_NODE];//将字符的编码结果存入bit数组中 charch;//要编码的字符 intweight;//字符出现的频率 }Coding; typedefstruct//输入字符信息 {HafNodearr[MAX_NODE];//数组结点信息 inttotal;//统计输入字符的种类个数 }HTree; voidstatistic_char(chartext[],HTree*t)/*统计字符出现的频率*/ { FILE*fp,*fp1;charch,ch1[20]; printf("请输入一批字符数据: \nA: 键盘输入B: 文件输入\n"); scanf("%c",&ch); if(ch=='A') scanf("%s",text); if(ch=='B') { printf("请输入文件名: \n"); scanf("%s",ch1); if((fp=fopen(ch1,"r"))==NULL) { puts("can'topenfile! ");exit(0); } fscanf(fp,"%s",text);fclose(fp); } fp1=fopen("zifu_quanzhi.txt","w+"); inttext_len=strlen(text); t=(HTree*)malloc(sizeof(HTree)); t->total=0; inti,j; for(i=0;i { for(j=0;j if(t->arr[j].ch==text[i])//要统计字符在之前已出现 { t->arr[j].weight++; break; } if(j==t->total)//记录新出现的字符 { t->total++; t->arr[j].ch=text[i]; t->arr[j].weight=1; } } printf("共有%d个数据项! \n",t->total); fprintf(fp1,"%d\n",t->total); printf("字符\t出现次数\n"); for(j=0;j { printf("%c\t%d\n",t->arr[j].ch,t->arr[j].weight); fprintf(fp1,"%c%d",t->arr[j].ch,t->arr[j].weight); } free(t);fclose(fp1); } voidHaffman(intweight[],charch[],intn,HafNodehaffTree[])/*生成哈夫曼树的函数*/ { inti,j,m1,m2,x1,x2; for(i=0;i<2*n-1;i++)//对所有结点初始化 { if(i { haffTree[i].weight=weight[i]; haffTree[i].ch=ch[i]; } else//对n-1个新结点权值清0 haffTree[i].weight=0; haffTree[i].parent=-1; haffTree[i].flag=0; haffTree[i].lchild=-1; haffTree[i].rchild=-1; } for(i=0;i { m1=m2=MAX_VALUE; x1=x2=0; for(j=0;j { if(haffTree[j].weight 已有根节点的叶子在第2次以后的比较中实际不需比较 { m2=m1;//m2取相比较权值的较大值 x2=x1;//x2取较大结点的下标 m1=haffTree[j].weight;//m1取相比较结点的较小权值 x1=j;//x1取该结点所在下标值 } elseif(haffTree[j].weight { m2=haffTree[j].weight; x2=j; } } haffTree[x1].parent=n+i;//x1,x2指向新节点,其值等于在haffTree数组中的下标 haffTree[x2].parent=n+i; haffTree[x1].flag=1;//标志位置1 haffTree[x2].flag=1; haffTree[n+i].weight=haffTree[x1].weight+haffTree[x2].weight; haffTree[n+i].lchild=x1; haffTree[n+i].rchild=x2; } FILE*fp; fp=fopen("haffman_tree.txt","w+"); printf("本次输入初始森林根节点数: %d\n",n);//输出叶子结点的个数 fprintf(fp,"%d\n",n);//并写入文件 for(i=0;i fprintf(fp,"%c%d%d%d\n",haffTree[i].ch,haffTree[i].parent,haffTree[i].lchild,haffTree[i].rchild); for(i=n;i<2*n-1;i++)//写入文件的新结点的信息 fprintf(fp,"%d%d%d\n",haffTree[i].parent,haffTree[i].lchild,haffTree[i].rchild); fclose(fp); } voidHaffmanCode(HafNodehaffTree[],intn,CodehaffCode[])/*生成哈夫曼编码的函数*/ { Code*cd=(Code*)malloc(sizeof(Code)); inti,j,child,parent; for(i=0;i { cd->start=n-1; cd->weight=haffTree[i].weight; cd->ch=haffTree[i].ch; child=i; parent=haffTree[child].parent; while(parent! =-1)//从叶子结点开始一直找到一棵树的根结点 { if(haffTree[parent].lchild==child) cd->bit[cd->start]=0; else cd->bit[cd->start]=1; cd->start--; child=parent; parent=haffTree[child].parent; } for(j=cd->start+1;j haffCode[i].bit[j]=cd->bit[j]; haffCode[i].start=cd->start+1; haffCode[i].weight=cd->weight; haffCode[i].ch=cd->ch; } free(cd); } voidInit(intweight[],charch[])/*初始化操作,生成哈夫曼树及哈夫曼编码*/ { FILE*fp; inti,j,n;charch1='\0'; printf("\n现在进行初始化操作,相关数据从文件zifu_quanzhi.txt导入...\n",ch1); if((fp=fopen("zifu_quanzhi.txt","r"))==NULL){ puts("can'topenfile! ");exit(0); } fscanf(fp,"%d\n",&n); HafNode*myHaffTree=(HafNode*)malloc(sizeof(HafNode)*(2*n+1)); Code*myHaffCode=(Code*)malloc(sizeof(Code)*n); for(i=0;i fscanf(fp,"%c%d",&ch[i],&weight[i]);//对应77行t->arr[j].ch,t->arr[j].weight fclose(fp); Haffman(weight,ch,n,myHaffTree);//CALLHaffman; HaffmanCode(myHaffTree,n,myHaffCode);//CALLHaffmanCode; fp=fopen("leaves.txt","w+"); printf("初始化后哈夫曼编码信息: \n字符\t权值\t二进制编码\n"); for(i=0;i { printf("%c\t%d\t",myHaffCode[i].ch,myHaffCode[i].weight); fprintf(fp,"%c%d",myHaffCode[i].ch,myHaffCode[i].weight); for(j=myHaffCode[i].start;j { printf("%d",myHaffCode[i].bit[j]); fprintf(fp,"%d",myHaffCode[i].bit[j]); } fprintf(fp,"\n"); printf("\n"); } fclose(fp);free(myHaffTree);free(myHaffCode); printf("初始化成功! \n"); printf("要清屏吗? (Y/N)\n"); scanf("%c",&ch1); if(ch1=='Y') system("cls"); } voidCaozuo_C()/*哈夫曼编码过程的函数,用于将文件编码*/ { FILE*fp,*fp1,*fp2; charzf[500]; if((fp=fopen("leaves.txt","r"))==NULL){ puts("can'topenfile! ");exit(0); } Codingch[100]; charc; inti=0; while(feof(fp)==0) { fscanf(fp,"%c%d%s\n",&ch[i].ch,&ch[i].weight,ch[i].bit);//对应150和161行myHaffCode输入的信息 i++; } fclose(fp); printf("现在进行编码操作...\n请选择: \nA.键盘输入B.文件输入\n"); scanf("%c",&c); if(c=='A') { printf("请输入字符串: \n"); scanf("%s",zf); } charch1[20],ch2[20]; intj; if(c=='B') { printf("请输入正文的文件名: \n");//对应输入的文件名为haffman.txt scanf("%s",ch1); if((fp1=fopen(ch1,"r"))==NULL){ puts("can'topenfile! ");exit(0); } } printf("请输入保存结果的文件名: \n"); scanf("%s",ch2); fp2=fopen(ch2,"w+"); if(c=='A') { printf("二进制编码为: "); intlen,k; len=strlen(zf); for(k=0;k for(j=0;j if(ch[j].ch==zf[k]) { fprintf(fp2,"%s",ch[j].bit); printf("%s",ch[j].bit); } printf("\n"); } if(c=='B') { printf("二进制编码为: "); while(feof(fp1)==0) { fscanf(fp1,"%c",&c); for(j=0;j if(ch[j].ch==c) { fprintf(fp2,"%s",ch[j].bit); printf("%s",ch[j].bit); } } fprintf(fp2,"\n"); printf("\n"); fclose(fp1); } fclose(fp2); printf("编码过程完成! 同时已将结果存入%s中.\n\n",ch2); } voidCaozuo_D()/*译码操作*/ { FILE*fp,*fp1,*fp2; if((fp=fopen("haffman_tree.txt","r"))==NULL){ puts("can'topenfile! ");exit(0); } inti,n; fscanf(fp,"%d\n",&n); HafNode*myHaffTree=(HafNode*)malloc(sizeof(HafNode)*(2*n+1));
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 赫夫曼编 译码器 说明书