1、用哈夫曼编码实现文件压缩用哈夫曼编码实现文件压缩实 验 报 告 课程名称 数据结构 实验学期 2011 至 2012 学年 第 2 学期学生所在系部 计算机学院 年级 2010级 专业班级 * 学生姓名 * 学号 * 任课教师 # 实验成绩 一、实验题目哈夫曼编码实现文件压缩二、实验目的:1、了解文件的概念。2、掌握线性链表的插入、删除等算法。3、掌握Huffman树的概念及构造方法。4、掌握二叉树的存储结构及遍历算法。5、利用Huffman树及Huffman编码,掌握实现文件压缩的一般原理。三、实验设备与环境:微型计算机、Windows 系列操作系统、Visual C+6.0软件。四、实验内
2、容:根据ASCII码文件中各ASCII字符出现的频率情况创建Haffman树,再将各字符对应的哈夫曼编码写入文件中,实现文件压缩。五、概要设计:本次实验采用将字符用长度尽可能短的二进制数位表示的方法,即对于文件中出现的字符,无须全部都用8位的ASCII码进行存储,根据他们在文件中出现的频率不同,我们利用Haffman算法使每个字符能以最短的二进制字符进行存储,以达到节省存储空间,压缩文件的目的。解决了压缩需采用的算法,程序的思路已然清晰:1统计需压缩文件中每个字符出现的频率。2将每个字符的出现频率作为叶子结点构建Haffman树,然后将树中结点引向其左孩子的分支标“0”,引向其右孩子的分支标“
3、1”;每个字符的编码即为从根到每个叶子的路径上得到的0、1序列,这样便完成了Haffman编码,将每个字符用最短的二进制字符表示。3打开需压缩文件,再将需压缩文件中的每个ASCII码对应的Haffman编码按bit单位输出。4文件压缩结束。六、详细设计:(1)构造Hufffman树的方法Hafffman算法构造Huffman树步骤:I. 根据给定的n个权值w1,w2,wn,构造n棵只有根结点的二叉树,令起权值为wj。II. 在森林中选取两棵根结点权值最小的树作左右子树,构造一棵新的二叉树,置新二叉树根结点权值为其左右子树根结点权值之和。III. 在森林中删除这两棵树,同时将新得到的二叉树加入森
4、林中。 .重复上述两步,直到只含一棵树为止,这棵树即哈夫曼树。对于Haffman的创建算法,有以下几点说明:a) 这里的Haffman树采用的是基于数组的带左右儿子结点及父结点下标作为存储结点的二叉树形式,这种空间上的消耗带来了算法实现上的便捷。b) 由于对于最后生成的Haffman树,其所有叶子结点均为从一个内部树扩充出去的,所以,当外部叶子结点数为m个时,内部结点数为m-1,整个Haffman树的需要的结点数为2m-1c) 初始化Hafffman树分两步进行,先将所有结点赋值,再将前m个叶子结点赋初值。d) 在查找权值最小并且父结点为空的两个结点时,通过逐个比较,将两结点的位置下标与权值分
5、别保存。方便在与其父结点建立联系时调用。2)压缩过程的实现:压缩过程的流程是清晰而简单的:1创建Haffman树2打开需压缩文件3将需压缩文件中的每个ASCII码对应的Haffman编码按bit单位输出4文件压缩结束。其中,步骤1和步骤3是压缩过程的关键。a) 步骤1:这里所要做工作是得到Haffman数中各叶子结点字符出现的频率并进行创建。b) 步骤3: 将需压缩文件中的每个ASCII码对应的Haffman编码按bit单位输出,这是本压缩程序中最关键的部分。这里涉及“转换”和“输出”两个关键步骤:“转换”部分大可不必去通过遍历Haffman树来找到每个字符对应的哈夫曼编码,可以将每个码值及其
6、对应的ASCII码存放于如下所示的结构体中:typedef structchar asciiCode;unsigned long haffCode;int haffCodeLen;HaffCode;创建由该结构体结点所组成的,长度为128的一维数组codeList128,且codeList中的下标和asciiCode满足下面的顺序存放关系:codeListi.asciiCode=i;这样的话,查找某个字符inChar的Haffman编码的工作便变得相当轻松了,如下:sHaffCode=codeListinChar.haffCode;数组codeList128的创建可以采用某种遍历方式下的按找到
7、的字符进行置数的方式,十分的方便。以下流程图采用的是前序遍历的方式创建:说明:1 在流程图中,youBiao中存放字符对应的Haffman编码,sDepth中存放其Haffman编码的长度。2 在代码的编写过程中,可用递归调用实现。 NY Y N Y N Y N N Y(3)“输出”部分是最重要的部分,也是最易出错的部分。每个字符要能合理的结束。这主要是为解压缩考虑的,比如在最后,这里涉及到C语言的位操作,要求这个算法能处理好以下几个问题:1)每个字符所对应的haffCode的比特位长度由523位不等长,不可少输,多输,输错任何一位,后一个字符的haffCode要紧跟在前一个字符的haffCo
8、de后面。 2)最后一个要输出的haffCode的最后一位,它恰好是位于最后一个有效字符的第一位,剩下的七个空位是要用无效的haffCode加以填充的。否则,如果填充的haffCode亦为某个ascii字符的haffCode时,那么在解压缩时,则该在原被压缩文件中不存在的字符便会无中生有的在解压后的文件中出现,这显然是不正确的,应在程序中加以处理。 NYN YY N(4)main 函数部分 N Y N Y七、测试结果及分析:运行结果:压缩情况:实验分析: 利用Huffman树进行编码进行文件的压缩,这一思想在上一学期的离散数学课程里我们有接触到,好在当时学的还不错,所以在构建Huffman树和
9、编码这一过程还是很容易接受的。困难就在于怎么构造出函数,构造出一个工程,做出一个能够顺利实现压缩的程序。这是动手能力,实践能力,需要长时间的编程训练作为基础。数据结构是计算机程序设计的重要理论技术基础,是计算机学科的核心课程之一。它将各个抽象的数据之间的关系建立起来,无论是线性的、循环的还是分支的,都是为了建立一种方便程序的实现和运行的结构,使得数据之间不再是孤立的。它能使得我们在编程时在脑海中显现更为清晰的数据关系画面。而且在学习数据结构时我们更应该联系所属语言(我们所学的是C语言版)的特性,这样才能更好的理解数据结构的思想体系。总的来说,这次实验带来的收获是很大的,提取文件数据、分析数据、
10、构建Huffman树、替换数据对文件进行压缩、输出文件,一次大的实验几乎运用到了我们一学期所学的所有知识。经过分、析调试和了解程序的代码,巩固了上课学习的知识。平时的小程序的编写是训练,而最后的综合实验是作为验收“产品”是否合格的重要依据之一。所以,我们平时的作业要认真独立完成,否则,在考试和做综合实验时都会很吃力的。八、教师评语:教 师 评 价评定项目ABCD评定项目ABCD算法正确界面美观,布局合理程序结构合理操作熟练语法、语义正确解析完整实验结果正确文字流畅报告规范题解正确其他:评价教师签名:年 月 日附程序:Code.c#include ECBTree.h#include MyAsse
11、rt.h#include #include #include #define LENGTH 128#define DEBUG 1#define REARPOS 80char dotTxt=.txt;char dotRer=.rer;int getBinLen(unsigned long inData);void main(int argc,char* argv) long wListLENGTH; unsigned long haffCodeListLENGTH; int haffCodeLenLENGTH; HaffCode haffListLENGTH; PHtTree myHtTree;
12、 char inputFileNameLENGTH,outputFileNameLENGTH; FILE* inputFile,* outputFile,* keyFile; int fileNameLen; char inData,outputData; unsigned long curCode,tmpBinData; int curLen,realLen,curIndex; int i; int count; unsigned long rearCode;/*rear data consult*/ int rearCodeLen; if (argc-keyFile not founded
13、-n); return;for(i=0;iLENGTH-1;i+) fscanf(keyFile,%d,&wListi); fscanf(keyFile,%d;,&wListi); myHtTree=haffmanAlgorithm(LENGTH,wList);for(i=0;irootIndex,0x000000,0,haffList); fprintf(stdout,haffCode List:rn);for(i=0;iLENGTH-1;i+) fprintf(stdout,%d,haffListi.haffCode); fprintf(stdout,%drn,haffListi.haff
14、Code); fprintf(stdout,haffCode List Len:rn);for(i=0;iLENGTH-1;i+) fprintf(stdout,%d,haffListi.haffCodeLen); fprintf(stdout,%drn,haffListi.haffCodeLen);if(DEBUG) printf(ntest start.n);curIndex=curLen=0;rearCode=haffListREARPOS.haffCode;rearCodeLen=haffListREARPOS.haffCodeLen;while(!feof(inputFile) co
15、unt=0; outputData=0x01; while(count8) if(curIndex=curLen) /1.get data. if(feof(inputFile) break; inData=fgetc(inputFile); if(inData=-1&feof(inputFile) if(count=0) outputData=-1; else/*the rear output adjust*/ for(i=0;i8-count;i+) outputData(rearCodeLen-1-i)&0x01); /* the consult below will make erro
16、r happen! outputData0) outputData(curLen-curIndex-1)&0x01; outputData=1; outputData|=(char)tmpBinData; /*-*/ curIndex+; count+; fputc(outputData,outputFile); if(DEBUG) printf(ntest ends.n); fclose(inputFile); fclose(outputFile); getchar(); return;int getBinLen(unsigned long inData) int i=0; if( inDa
17、ta=0) return 1; else while(inData!=0) inData/=2; i+; return i;ECBTree.c#include ECBTree.h#include MyAssert.h#include #include PHtTree haffmanAlgorithm(int m,EBTreeType* w) PHtTree pht; int i,j; int firstMinIndex,secondMinIndex; int firstMinW,secondMinW; pht=(PHtTree)malloc(sizeof(struct HtTree); ass
18、ertF(pht!=NULL,in haffman algorithm,mem apply failuren); /*Initialize the tree array*/ for(i=0;ihti.llinkIndex=-1; pht-hti.rlinkIndex=-1; pht-hti.parentIndex=-1; if(ihti.ww=wi; pht-hti.info=(char)i; else pht-hti.ww=-1; for(i=0;im-1;i+)/new Inner Node Num:m-1 firstMinW=MAXCHAR; firstMinIndex=-1; seco
19、ndMinW=MAXCHAR; secondMinIndex=-1; for(j=0;jhtj.wwhtj.parentIndex=-1) /trans minFirst info to minSecond info secondMinIndex=firstMinIndex; secondMinW=firstMinW; /set new first min node. firstMinIndex=j; firstMinW=pht-htj.ww; else if(pht-htj.wwhtj.parentIndex=-1) secondMinW=pht-htj.ww; secondMinIndex
20、=j; /Construct a new node. m+i is current new nodes index pht-htfirstMinIndex.parentIndex=m+i; pht-htsecondMinIndex.parentIndex=m+i; pht-htm+i.ww=firstMinW+secondMinW; pht-htm+i.llinkIndex=firstMinIndex; pht-htm+i.rlinkIndex=secondMinIndex; pht-rootIndex=m+i; return pht;/*Invoke:preHaffListMake(myHt
21、Tree,myHtTree-rootIndex,0x00,0,myList)*/void preHaffListMake(PHtTree inTree,int rootIndex,unsigned long youBiao,int sDepth,HaffCode* inList) if(inTree-htrootIndex.llinkIndex=-1&inTree-htrootIndex.rlinkIndex=-1) inListinTree-htrootIndex.info.haffCode=youBiao; inListinTree-htrootIndex.info.haffCodeLen
22、=sDepth; else preHaffListMake(inTree,inTree-htrootIndex.llinkIndex,youBiaohtrootIndex.rlinkIndex,(youBiao1)|0x01,sDepth+1,inList); MyAssert.c#include myAssert.h#include #include void assertF(int condition,char* errorMsg) if(!condition) printf(n%sn,errorMsg); abort(); ECBTree.h#ifndef ECBTREE_H#defin
23、e ECBTREE_H#define EBTreeType long#define MAXCHAR 30000#define MAXNODE 300struct HtNode EBTreeType ww; char info; int parentIndex; int llinkIndex; int rlinkIndex;struct HtTree struct HtNode htMAXNODE; int rootIndex;typedef struct HtTree* PHtTree;typedef struct char asciiCode; unsigned long haffCode;
24、 int haffCodeLen;HaffCode;extern PHtTree haffmanAlgorithm(int m,EBTreeType* w);extern void preHaffListMake(PHtTree inTree,int rootIndex,unsigned long youBiao,int sDepth,HaffCode* inList);#endifGlobal.h#ifndef GLOBAL_H#define GLOBAL_H#define Type long#endifMyAssert.h/*myAssert.h*/#ifndef MYASSERT_H#define M
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1