1、哈夫曼算法及其应用哈夫曼算法及其应用一、问题描述 给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树。哈夫曼编码是一种根据哈夫曼树对文件进行编码的方式。哈夫曼编码是可变字长编码的一种。本次课程设计是对一个已建文本文件,统计该文件中各字符频率,对各字符进行Huffman编码,将该文件翻译成Huffman编码文件,再将Huffman编码文件翻译成原文件。压缩文件即读文件,统计文件中的字符个数,对文件进行哈夫曼编码和译码,并将编码译码后的字符存储在文件中。二、基本要求 程序要求实现以下功能: 1统计文本文件中各字符的出现次数(涉及读文件,
2、统计字符个数); 2对文件中的字符进行哈夫曼编码,并存储入字符编码文件; 3根据字符编码文件对文本文件内容进行编码; 4根据字符编码文件和已编码文件的内容进行译码; 5能够输出原文、编码表、文本文件编码、译文。3、测试数据 In its medical literature, the Food and Drug Administration states that hot water comfortable enough for washing hands is not hot enough to kill bacteria, but is more effective than cold w
3、ater because itremoves oils from the hand that can harbor bacteria.四、算法思想 1、哈夫曼树建立算法: 1)根据给定的n个权值 W1,W2,W3Wn 构成n棵二叉树的集合T1, T2, Tn,其中Ti中只有一个权值为Wi的根结点,左右子树均为空。 2)在F中选取两棵根结点的权值最小的树作为左、右子树一构造一棵新的二叉树,且置新的二叉树的根结点的权值为左、右子树上根结点的权值之和。 3)在F中删除这两棵中权值最小的树,同时将新得到的二叉树加入F中。 4)重复2)3)直到F中仅剩一棵树为止,这棵树就是哈夫曼树。 2、哈夫曼编码算法
4、: 通过从哈夫曼树根结点开始,对左子树分配代码“1”,右子树分配代码“0”,一直到达叶子结点为止,然后将从树根沿每条路径到达叶子结点的代码排列起来,便得到了哈夫曼编码。3、对文件字符编码算法:逐一读取文件中字符,在哈夫曼编码表查找对应字符,读取其编码并写入文件,如此循环直至结束。 4、哈夫曼译码算法: 根据编码用的哈夫曼树,从根结点出发,逐个读入电文中的二进制码;若代码为“1”,则走左子树的根结点,否则走向右子树的根结点;一旦到达叶子结点,便译出代码所对应的字符。然后又重新从根结点开始继续译码,直到二进制电文结束。五、模块划分1Void InitHT(HuffmanT T) 初始化Huffma
5、n树。2Void SelectMin(HuffmanT T, int n, int &p1, int &p2) 找到权重最小的叶子。 3Void LoadHuffmanFile(HuffmanT T) 加载文件。 4Void CreatHT(HuffmanT T) 构造Huffman树。5Void CharSetHuffmanEncoding(HuffmanT T, HuffmanCode H) 根据Huffman树求Huffman编码表。6Void EncodingHuffmanT(HuffmanT T, HuffmanCode H) 对文件编码。7Void DecdingHuffmanT(
6、HuffmanT T, HuffmanCode H) 根据Huffman编码、译码。8Void PrintHuffmanT(HuffmanT T) 打印Huffman权重表。9Void PrintHuffmanH(HuffmanT T, HuffmanCode H) 打印Huffman编码表。10Void MainMenue() 主菜单。提供相关的操作提示。11Int main() 主函数。用个while循环和switch选择结构进行进行循环交互性操作。六、数据结构/(ADT) 1、哈夫曼树的存储结构: typedef struct char ch; /字符 int weight; /字符权重
7、 int lchild; /左子 int rchild; /右子 int parent; /双亲 THNODE; 2、哈夫曼编码表的存储结构: typedef struct char ch; /存储字符 char bitsMAX_C + 1; /字符编码位串 CodeNode;七、源程序/Huffman.cpp 源代码如下:#include #include #include #define MAX_C 256 /定义最大字符数#define MAX_N 512 /定义最大Huffman节点个数#define N 50/*Huffman Tree 结构*/typedef struct char
8、 ch; /字符 int weight; /字符权重 int lchild; /左子 int rchild; /右子 int parent; /双亲THNODE;typedef THNODE HuffmanTMAX_N;/*Huffman 编码表结构*/typedef struct char ch; /存储字符 char bitsMAX_C + 1; /字符编码位串CodeNode;typedef CodeNode HuffmanCodeMAX_C;HuffmanCode H;/*全局变量*/int n; /指示待编译文件的字长char filename20;/*初始化Huffman树*/vo
9、id InitHT(HuffmanT T) int i; for (i = 0; i MAX_N; i+) Ti.ch = 0; Ti.weight = 0; Ti.lchild = -1; Ti.rchild = -1; Ti.parent = -1; /*找到权重最小的叶子*/void SelectMin(HuffmanT T, int n, int &p1, int &p2) int i; int j; for (i = 0; i 0) p1 = i; break; for (j = i + 1; j 0) p2 = j; break; for (i = 0; i Ti.weight)
10、& (Ti.parent = -1) & (p2 != i) & (Ti.weight 0) p1 = i; for (j = 0; j Tj.weight) & (Tj.parent = -1) & (p1 != j) & (Tj.weight 0) p2 = j; /*加载文件*/void LoadHuffmanFile(HuffmanT T) unsigned int i; int j = 0; char c; int aMAX_C; FILE *fp; printf(Input file name: ); scanf(%s, filename); if (fp = fopen(file
11、name, rb) = NULL) printf(Cant open %sn, filename); exit( 0 ); for (i = 0; i MAX_C; i+) ai = 0; fseek(fp, 0, SEEK_SET); while ( 1 )/( !feof(fp) ) fread(&c, sizeof(unsigned char), 1, fp); if (feof(fp) break; a(unsigned int)c+; fclose(fp); /*统计输入文件的字符及其权重并存放到树T*/ for (i = 0; i MAX_C; i+) if (ai != 0) T
12、j.ch = (unsigned char)i; Tj+.weight = (unsigned int)ai; n = j;/*构造huffam树,T2 * n - 1为其根*/void CreatHT(HuffmanT T) int i,p1,p2; LoadHuffmanFile(T); /加载被编码文件 for (i = n; i 2 * n - 1; i+) SelectMin(T, i - 1, p1, p2); Tp1.parent = Tp2.parent = i; Ti.lchild = p1; Ti.rchild = p2; Ti.weight = Tp1.weight +
13、Tp2 .weight; /*根据Huffman T 求Huffman编码表H*/void CharSetHuffmanEncoding(HuffmanT T, HuffmanCode H) int c; /指示T中孩子的位置 int p; /指示T中双亲的位置 int i; int start; /指示编码在cd中的位置 char cdN; /临时存放编码 for (i = 0; i = 0) /直到回溯到Tc是树根位置 cd-start = (Tp.lchild = c) ? 0 : 1; c = p; strcpy(Hi.bits, &cdstart); /复制临时编码到编码表中 /*对
14、文件编码,将结果保存到codefile.txt中*/void EncodingHuffmanT(HuffmanT T, HuffmanCode H) char c; FILE *in,*fp; int j,l; char encodefile20,tempMAX_C; if (in = fopen(filename, rb) = NULL) printf(Read %s fail!n, encodefile); exit(1); CharSetHuffmanEncoding(T, H); printf(Input encode file name: ); gets( encodefile );
15、 if (fp = fopen(encodefile, wb) = NULL) printf(Write %s fail!n, encodefile); exit(1); fread(&c, sizeof(unsigned char), 1, in); fwrite(&c, sizeof(unsigned char), 1, fp); fseek(in, 0, SEEK_SET); fseek(fp, 0, SEEK_SET); while ( 1 )/( !feof( in ) fread(&c, sizeof(unsigned char), 1, in); if (feof(in) bre
16、ak; for (j = 0; j n; j+) if (c = Hj.ch) l = 0; while (Hj.bitsl != 0) templ = Hj.bitsl; l+; int m = 0; while ( l- ) fwrite(&tempm+, sizeof(unsigned char), 1, fp); fclose(fp); printf(Encoding file has saved into %s!n, encodefile);/*根据Huffman编码、译码*/void DecodingHuffmanT(HuffmanT T, HuffmanCode H) int i
17、; /指示Huffman tree叶子个数 FILE *fp,*fp1; char ch,ch120,ch220; printf(Input encode file name: ); scanf(%s, ch1); printf(Input decode file name: ); scanf(%s, ch2); fp = fopen(ch1, rb); fp1 = fopen(ch2, wb); /根据Huffman树对Huffman编码 译码 i = 2 * n - 2; fseek(fp, 0L, SEEK_SET); fseek(fp1, 0L, SEEK_SET); while (!
18、feof(fp) fread(&ch, sizeof(unsigned char), 1, fp); if (ch = 0) /若编码为o,则找此结点的左子树; i = Ti.lchild; if (ch = 1) /若编码为,则找此结点的右子树; i = Ti.rchild; if (i n) fwrite(&Ti.ch, sizeof(unsigned char), 1, fp1); i = 2 * n - 2; fclose(fp); fclose(fp1); printf(Decoding accomplished!nThe result has save input %s.n,ch2
19、); getchar();/*打印Huffman权重表*/void PrintHuffmanT(HuffmanT T) int i; FILE *fp; if (fp = fopen(treeprint.txt, wb) = NULL) printf(Open treeprint.txt fail!n); exit(1); printf(nLeaf&weight of the Huffman tree is below:n); for (i = 0; i 0) printf(n); if (Ti.weight 0) fprintf(fp, %c:%d , Ti.ch, Ti.weight);
20、printf(%c: %d , Ti.ch, Ti.weight); fclose(fp); printf(nLeaf&weight of the Huffman tree saved in treeprint.txtnn);/*打印Huffman编码表*/void PrintHuffmanH(HuffmanT T, HuffmanCode H) int i; FILE *fp; CharSetHuffmanEncoding(T, H); if (fp = fopen(codeprint.txt, wb) = NULL) printf(Open codeprint.txt fail!n); e
21、xit(1); for (i = 0; i 0) printf(n); printf(%c: %sn, Ti.ch, Hi.bits); fprintf(fp, %c:%s , Ti.ch, Hi.bits); fclose(fp); printf(nHuffman tree code saved in codeprint.txt!nn);/*主菜单*/void MainMenue() fflush( stdin ); printf(n* Main Menue *n); printf(* *n); printf(* 1. Load to be dealt file. *n); printf(*
22、 2. Show Huffman code list. *n); printf(* 3. Show Huffman weight list. *n); printf(* 4. Encoding Huffman file. *n); printf(* 5. Decoding Huffman file. *n); printf(* 6. Exit. *n); printf(* *n); printf(*n);/*主函数开始*/int main() int flag = 1; char ch10; HuffmanT T; /定义Huffman树 HuffmanCode H; /定义Huffman编码
23、表 InitHT(T); /初始化Huffman树 while ( flag ) MainMenue(); printf(Please input your choice(16): ); gets( ch ); switch ( ch0 ) case 1: CreatHT(T); break; case 2: PrintHuffmanH(T, H); break; case 3: PrintHuffmanT(T); break; case 4: EncodingHuffmanT(T, H); break; case 5: DecodingHuffmanT(T, H); break; case
24、6: exit(1); default: printf(Input error!n); break; return 0;八、测试情况 程序的测试结果如下: 建立哈夫曼树、打印编码表正确。 打印权重表正确。 哈夫曼编码正确。 哈夫曼译码正确,退出正确。九、参考文献 1、严蔚敏,数据结构 C语言,清华大学出版社。 2、谭浩强,c语言程序设计,清华大学出版社。小结 课程设计是数据结构课程教学必不可缺的一个重要环节,是培养学生综合运用所学知识,发现、提出、分析和解决实际问题,锻炼实践能力的重要环节。同时可加深学生对该课程所学内容的进一步的理解与巩固,是将计算机课程与实际问题相联接的关键步骤。通过课程设
25、计,能够提高分析问题、解决问题,从而运用所学知识解决实际问题的能力。 通过本次数据结构的课程设计,我理解很多之前上课没懂的知识,对求哈夫曼树及哈夫曼编码/译码的算法有了更加深刻的了解,更巩固了课堂中学习有关于哈夫曼编码的知识,真正学会一种算法了。当求解一个算法时,不是拿到问题就不加思索地做,而是首先要先对它有个大概的了解,接着再详细地分析每一步怎么做,无论自己以前是否有处理过相似的问题,只要按照以上的步骤,必定会顺利地做出来。 这次课程设计是我们大三来做的第一次了,我在编辑中犯了不应有的错误,如设计统计字符和合并时忘记应该怎样保存保存数据,在其他同学的帮助下明确并改正了错误和疏漏,使我们的程序
26、有了更高的质量。在设计过程中逐渐积累了一些基本的经验,所以做到后来逐渐顺利,但也还是会遇到一些这样或那样的问题,通过本次课程设计,进一步适应团队合作开发规模稍大的程序,体会个人开发与团队开发的利弊,加强团队协作与团队内的沟通,表达能力。感受对本专业说学习的多门课程知识进行综合应用,将多门课程的知识融合贯通。 同时通过这次设计也获得一些编程经验:编程时要认真,出现错误要及时找出并改正,遇到问题要去查相关的资料。反复的调试程序,把各个注意的问题要想到;同时要形成自己的调试程序的风格,从每个细节出发,不放过每个知识点。另外,要注意符号的使用。 本次课程设计虽然实现了哈夫曼编码/译码等要求,但由于时间等各方面原因,仍有一些问题没有解决,例如一些要求输入判断时判断不严格、操作界面不够美观等,总体上还有待改进。1)2)3)
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1