哈夫曼编码课设说明书.docx
- 文档编号:8002343
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:35
- 大小:166.82KB
哈夫曼编码课设说明书.docx
《哈夫曼编码课设说明书.docx》由会员分享,可在线阅读,更多相关《哈夫曼编码课设说明书.docx(35页珍藏版)》请在冰豆网上搜索。
哈夫曼编码课设说明书
*******************
实践教学
*******************
计算机与通信学院
2016年秋季学期
算法与数据结构课程设计
题目:
哈夫曼的编/译码系统敢死队问题
专业班级:
姓名:
学号:
指导教师:
成绩:
_______________
摘要
哈夫曼编译系统是为了实现一个利用哈夫曼算法的编码和译码系统。
比如,再利用电报进行通讯时,需要将文字转换成由二进制的字符组成的字符串。
但是在传送过程中,总希望长度能够尽可能的短,于是我们想采用长度不等的编码。
但是这种编码必须遵循:
任何一个字符的编码都不是另一个字符编码的前缀。
因此哈夫曼编译系统能够正确的使得对于输入的字符进行编码以及译码,并且是的在译码过程中不会出错,同时能够将编码以及译码的结果正确的存入文件当中。
敢死队问题主要是用两种数据结构方法实现敢死队问题。
从1到M个数据,采用链表和队列存储,由于是轮回数数,需要循环,因此所用的链表是单向循环链表,所用的队列是循环队列。
战士去执行任务,若没有完成任务,则需要把该战士的号码从队列或者链表中删除。
由于要求出从第几号战士开始计数才能让排长最后一个留下来而不去执行任务,所以程序从1号到M号逐个开始计数,从计数的战士开始的第五个战士去执行任务,若没完成任务,则删除之,从被删除战士下一个号码开始计数,后边的第五个战士接着开始去执行任务,若没完成任务,则删除之,如此循环,直到最后一个战士,若最后一个战士是排长,即1号,则终止循环,记下开始计数的战士的号码即为所求。
关键词:
哈夫曼树;队列;链表;指针
一.哈夫曼码的编/译码系统
编写一个哈夫曼码的编/译码系统,实现对输入的文本信息自动统计并依此为依据建立一个哈夫曼码的编/译码系统。
1.采用类语言定义相关的数据类型
哈夫曼码的编/译系统主要采用的数据结构为树和链表和数组。
其中链表是一种物理存储单元上非连续、非顺序的存储结构,它既可以表示线性结构,也可以用于表示非线性结构,结点可以动态生成。
而树是包含n(n>0)个结点的有穷集合K,且在K中定义了一个关系N,N满足以下条件:
(1)有且仅有一个结点K0,他对于关系N来说没有前驱,称K0为树的根结点。
简称为根。
(2)除K0外,K中的每个结点,对于关系N来说有且仅有一个前驱。
(3)K中各结点,对关系N来说可以有m个后继(m>=0)
输入/输出数据:
数据类型:
数据
字符型
权值
浮点型
父结点,左右孩子结点
整型
节点数
整型
开始位置
整型
表A-1主要数据类型
2.算法设计
●构造哈夫曼树的算法
在哈夫曼树中,没有度为1的结点,这类二叉树称为严格二叉树。
那么对于一颗含有n个结点的哈弗曼树共有2n-1个结点所以哈夫曼算法可以用一维数组实现。
显然每个结点的存储结构都应该有一个域存放权值;构成Huffman树之后,为求编码需从叶子结点出发走一条从叶子到根的路径,而为译码需从根出发走一条从根到叶子的路径。
对每个结点而言,既需知双亲的消息,又需知孩子结点的消息。
因此,可设定一个静态三叉链表来实现。
具体算法描述如下:
structhufmtreenode{//定义哈弗曼树结点数据类型
chardata;
floatweight;//结点权值
intparent,lchild,rchild;
hufmtree*BuildHuffmanTree(hufmtree*tree){//构建叶子结点已初始化的哈夫曼树
//tree中所有叶子结点已初始化
inti,j,p1,p2,m;
floatsmall1,small2;
m=2*(tree->n)-1;
for(i=tree->n;i { tree->node[i].parent=-1; tree->node[i].lchild=-1; tree->node[i].rchild=-1; tree->node[i].weight=0.0; } for(i=tree->n;i { small1=small2=MAXVAL; for(j=0;j<=i-1;j++) { if(tree->node[j].parent==-1&&tree->node[j].weight<=small1small1=tree->node[j].weight;p1=j; for(j=0;j<=i-1;j++) { if(tree->node[j].parent==-1&&tree->node[j].weight<=small2&&(j! =p1)) small2=tree->node[j].weight; p2=j; tree->node[p1].parent=tree->node[p2].parent=i; tree->node[i].weight=tree->node[p1].weight+tree->node[p2].weight; tree->node[i].lchild=p1; tree->node[i].rchild=p2; } returntree; } ●哈夫曼编码算法 求哈夫曼编码,实质上就是在已建好的哈夫曼树中,从叶子结点开始,沿结点的双亲域回退到根节点,每回退一步,就走过了哈夫曼树的一个分支,从而得到一位哈夫曼编码值,由于一个字符的哈弗曼编码是从根节点到相应的叶子结点所经过的路径上各分支所组成的0、1序列,因此先得到的分支代码为所求编码的低位码,后得到的分支码为所求编码的高位码。 可以设置一个结构数组用来存放各字符的哈夫曼码信息。 具体算法描述如下: while(! feof(codefile)) { for(i=2*tree->n-2;tree->node[i].lchild>=0&&tree->node[i].rchild>=0&&ch! =EOF;) { if(ch=='0') i=tree->node[i].lchild; elseif(ch=='1') i=tree->node[i].rchild; else{ printf("\n存在异常字符%c,不能正确译码。 \n",ch); return; } if(i==-1)//在哈夫曼树中找不到对应叶子结点 { printf("\n编码与当前哈夫曼树结构不相符,不能正确译码。 \n",ch); fclose(decodefile); return; } ch=fgetc(codefile); } 3.函数的调用关系图 图A-1各程序模块之间的层次(调用)关系图 4.调试分析 (1)问题1 ●问题描述: 编码过程中字符串编码总是缺少很多位,甚至不能编码一些字符。 ●问题分析: 字符串编码总是缺少很多位,说明导致这种情况的可能是节点不够多,致使编码没空间存储。 ●解决方法: 初始化霍夫曼链表的节点不够,如果假设字符串有n个,那链表节点至少得有2n-1个,比如对4个字符串编码,先在4个字符里选2个权值最小的字符,2个字符权值相加,生成新的一个节点存储,现在还剩3个节点,同理3选2,生成新节点,剩余一个节点最后与上一步生成的节点配对,因此共需要生成3个新节点来存储。 (2)问题2 ●问题描述: 程序运行中,当创建树时,无法将树的元素存入到其中。 ●问题分析: 无法存入其中,可能有两方面原因,第一: 没有初始化树,即没有申请空间;第二方面: 可能是树的结构体定义出现错误。 ●解决方法: 在树的创建中,首先对其进行初始化,申请存储空间,然后再输入树的元素,经过调试,结果正确。 (3)算法的时间复杂度为O(n²),空间复杂度为S(n)。 5.测试结果 (1)打开源文件统计各字符及权值信息并存入data.txt文件中 图A-2测试图 (2)将统计出的权值信息进行哈夫曼编码 图A-3测试图 (3)将编码内容存入CodeFile.txt文件中 图A-4测试图 (4) 将CodeFile.txt文件中的内容译码 图A-5测试图 (5)成功译码把原字符信息存入DeCodeFile.txt文件中 图A-6测试图 6.源程序(带注释) #include #include #include #defineMAXVAL10000.0 structhufmtreenode{//定义哈弗曼树结点数据类型 chardata; floatweight;//结点权值 intparent,lchild,rchild;//父结点,左、右孩子结点 }; structhufmtree{//哈弗曼树数据类型 hufmtreenode*node;//结点数组(根据n的值动态分配) intn;//定义叶子结点数 }; structCodetype{//哈弗曼编码数据类型 char*bits;//n为为哈夫曼树中叶子结点的数目,编码的长度不可能超过n intstart;//编码实际在编码数组里的开始位置 }; voidSortHufmtree(hufmtree*tree){//将哈夫曼树n个叶子结点由大到小排序 inti,j,k; hufmtreenodetemp; if(tree==NULL) return; for(i=0;i { k=i; for(j=i+1;j if(tree->node[j].weight>tree->node[k].weight) k=j; if(k! =i) { temp=tree->node[i]; tree->node[i]=tree->node[k]; tree->node[k]=temp; } } } Codetype*HuffmanCode(hufmtree*tree){//哈弗曼编码的生成 inti,j,p,k; Codetype*code; if(tree==NULL) returnNULL; code=(Codetype*)malloc(tree->n*sizeof(Codetype)); for(i=0;i { printf("%c",tree->node[i].data);//打印字符信息 code[i].bits=(char*)malloc(tree->n*sizeof(char)); code[i].start=tree->n-1; j=i; p=tree->node[i].parent; while(p! =-1){ if(tree->node[p].lchild==j) code[i].bits[code[i].start]='0'; else code[i].bits[code[i].start]='1'; code[i].start--; j=p; p=tree->node[p].parent; } for(k=code[i].start+1;k printf("%c",code[i].bits[k]); printf("\n"); } returncode; } hufmtree*BuildHuffmanTree(hufmtree*tree){//构建叶子结点已初始化的哈夫曼树 //tree中所有叶子结点已初始化 inti,j,p1,p2,m; floatsmall1,small2; m=2*(tree->n)-1; for(i=tree->n;i { tree->node[i].parent=-1; tree->node[i].lchild=-1; tree->node[i].rchild=-1; tree->node[i].weight=0.0; } for(i=tree->n;i { small1=small2=MAXVAL; for(j=0;j<=i-1;j++) { if(tree->node[j].parent==-1&&tree->node[j].weight<=small1) { small1=tree->node[j].weight; p1=j; } } for(j=0;j<=i-1;j++) { if(tree->node[j].parent==-1&&tree->node[j].weight<=small2&&(j! =p1)) { small2=tree->node[j].weight; p2=j; } } tree->node[p1].parent=tree->node[p2].parent=i; tree->node[i].weight=tree->node[p1].weight+tree->node[p2].weight; tree->node[i].lchild=p1; tree->node[i].rchild=p2; } returntree; } hufmtree*CreateHuffmanTreeFromSourceFile(){//通过解析源文件建立哈夫曼树 FILE*textfile,*datafile; charch,sourcefilename[100]; inti,j=0,n=0; floatcount[128];//用于统计字符在源文件中出现的次数,27表示26个英文字母和1个空格字符 hufmtree*tree; //打开一个源文件 printf("\n请输入源文件所在路径: \n"); scanf("%s",sourcefilename); if((textfile=fopen(sourcefilename,"r"))==NULL){ printf("\n找不到文件%s\n",sourcefilename); returnNULL; } for(i=0;i<128;i++) count[i]=0; //对源文件中各字符的个数统计 ch=fgetc(textfile); while(! feof(textfile)){ for(i=0;i<128;i++) if(ch==char(i)){ count[i]++; break; } ch=fgetc(textfile); } //将统计结果写入权值信息文件data.txt中,并构建哈夫曼树 datafile=fopen("data.txt","w"); for(i=0;i<128;i++) if(count[i]! =0) n++; fprintf(datafile,"%d\n",n); tree=(hufmtree*)malloc(sizeof(hufmtree)); tree->node=(hufmtreenode*)malloc((2*n-1)*sizeof(hufmtreenode)); tree->n=n; printf("\n源文件的字符集及其权值信息如下: \n"); for(i=0;i<128;i++) if(count[i]! =0) { fprintf(datafile,"%c%f\n",char(i),count[i]); printf("%c%.0f\n",char(i),count[i]); tree->node[j].data=char(i); tree->node[j].weight=count[i]; tree->node[j].parent=-1; tree->node[j].lchild=-1; tree->node[j].rchild=-1; j++; } SortHufmtree(tree); BuildHuffmanTree(tree); fclose(textfile); fclose(datafile); printf("\n哈夫曼树建立完毕,已将权值信息保存至data.txt\n"); returntree; } hufmtree*CreateHuffmanTreeByInput(){//通过用户输入建立哈夫曼树 intn; hufmtree*tree; inti,m; FILE*datafile; tree=(hufmtree*)malloc(sizeof(hufmtree)); datafile=fopen("data.txt","w"); //由用户输入字符与权值信息并将其写入data.txt,同时进行哈夫曼树初始化 printf("请输入字符数: "); scanf("%d",&n); if(n<=0) { printf("\n您的输入有误。 \n"); returnNULL; } tree->node=(hufmtreenode*)malloc((2*n-1)*sizeof(hufmtreenode)); tree->n=n; m=2*n-1; for(i=0;i { tree->node[i].parent=-1; tree->node[i].lchild=-1; tree->node[i].rchild=-1; tree->node[i].weight=0.0; } fprintf(datafile,"%d\n",n); for(i=0;i { printf("输入第%d个字符及其权值: ",i+1); tree->node[i].data=getche(); scanf("%f",&tree->node[i].weight); fprintf(datafile,"%c%f\n",tree->node[i].data,tree->node[i].weight); } fclose(datafile); //哈夫曼树构建 SortHufmtree(tree); BuildHuffmanTree(tree); printf("\n哈夫曼树建立完毕,已将权值信息保存至data.txt\n"); returntree; } hufmtree*CreateHuffmanTreeFromDataFile(){//通过读取权值信息文件建立哈夫曼树 FILE*datafile; inti,n; hufmtree*tree; if((datafile=fopen("data.txt","r"))==NULL){ printf("\n哈夫曼树尚未建立\n"); returnNULL; } //哈夫曼树初始化 fscanf(datafile,"%d",&n); fgetc(datafile); tree=(hufmtree*)malloc(sizeof(hufmtree)); tree->node=(hufmtreenode*)malloc((2*n-1)*sizeof(hufmtreenode)); tree->n=n; for(i=0;i tree->node[i].data=fgetc(datafile); fscanf(datafile,"%f\n",&tree->node[i].weight); tree->node[i].parent=-1; tree->node[i].lchild=-1; tree->node[i].rchild=-1; } fclose(datafile); //哈夫曼树构建 SortHufmtree(tree); BuildHuffmanTree(tree); returntree; } hufmtree*Encoding(hufmtree*tree){//对源文件进行编码并将其输出至新文件 FILE*textfile,*codefile; charch,sourcefilename[50]; inti,j; Codetype*code; if(tree==NULL)//如果内存中尚未建立哈夫曼树 {//试从data.txt中读取权值信息并建立哈夫曼树 tree=CreateHuffmanTreeFromDataFile(); if(tree==NULL) returnNULL; } //读取源文件 printf("\n请输入源文件所在路径: \n"); scanf("%s",sourcefilename); if((textfile=fopen(sourcefilename,"r"))==NULL){ printf("\n找不到文件%s\n",sourcefilename); returnNULL; } //打印源文件内容 printf("\n源文件的原文如下: \n"); ch=fgetc(textfile); while(! feof(textfile)){ printf("%c",ch); ch=fgetc(textfile); } //编码 printf("\n字符集的哈夫曼编码如下: \n"); code=HuffmanCode(tree); //将源文件中各字符编码并写入codefile codefile=fopen("CodeFile.txt","w"); fseek(textfile,0,SEEK_SET); ch=fgetc(textfile); while(! feof(textfile)) { for(i=0;i if(ch==tree->node[i].data){ for(j=c
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 哈夫曼 编码 说明书