数据结构课程设计
课题名称: 哈夫曼编码/译码器
专业: 班级:
姓名: (组长) 学号: 成绩:
姓名: (组员) 学号: 成绩:
姓名: (组员) 学号: 成绩:
指导教师:
完成日期: 2018 年 12 月 17 日
任 务 书
题目:哈夫曼编码/译码器 |
设计内容及要求: 1.课程设计任务内容 1)将权值数据存放在数据文件(文件名为data.txt,位于执行程序的当前目录中) 2)分别采用动态和静态存储结构 3)初始化:键盘输入字符集大小n、n个字符和n个权值,建立哈夫曼树; 4)编码:利用建好的哈夫曼树生成哈夫曼编码; 5)输出编码; 6)实现译码功能:即随机输入一组字符,实现编码,并能够根据编好的码翻译成输入的字符。
通过一个具体的程序加深对于数据结构中算法的认识,增强动手能力,希望增强对存储结构的认识,懂得如何利用哈夫曼树的特点对字符进行编码和解码。 |
开发环境: DEVC
|
实现目标:
|
摘 要
在当前这个信息高速发展的时代,每时每刻都在进行着大量的信息传递,一切多离不开信息,如如何采用有效的数据压缩技术来节省数据文件的存储空间和计算机网络的传送时间已经越来越引起人们的重视。哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。
哈夫曼编码的的应用广泛,利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为各个字符对应的编码,这就是哈夫曼编码。
通常我们把数据压缩的过程乘坐便阿门,解压缩的过程称为解码。电报通信时传递位子的二进制码形式的字符串。但在信息传递时,总希望总长度尽可能最短,即采用最短码。
关键词:哈夫曼树 编码 解码
Abstract
In the current era of high-speed development of information, a large amount of information transfer is going on every moment. Information is indispensable for everything. For example, how to use effective data compression technology to save storage space of data files and transfer time of computer network has attracted more and more attention. Huffman coding is a widely used and very effective data compression technology.
Huffman coding is widely used, and the binary coding for communication obtained by using Huffman tree is called Huffman coding. There is a path from the root to each leaf in the tree, and each branch on the path is agreed: the branch pointing to the left subtree represents a " 0" code, the branch pointing to the right subtree represents a " 1" code, and the sequence of " 0" or " 1" on each path is taken as the corresponding code for each character, which is Huffman coding.
Usually we call the process of data compression an amen, and the process of decompression is called decoding. A string in the form of a binary code that conveys a seat in telegraphic communication. However, when transmitting information, it is always hoped that the total length will be as short as possible, that is, the shortest code will be used.
Key words: Huffman tree coding and decoding
学 号 |
姓 名 |
撰写章节 |
16 |
|
引言 课题分析 设计思路 模块划分 |
36 |
|
关键算法描述 程序设计流程图 关键算法描述 |
01 |
|
重要数据结构和变量说明 运行结果 使用说明 |
目 录
1 引 言 1
2 课题分析 2
3 课题设计 3
3.1设计思路 3
3.2模块划分 4
3.3重要数据结构和变量说明 6
3.4关键算法描述 7
3.5程序设计流程图 8
4 程序运行结果 10
5 软件使用说明 12
6 结 论 15
参考文献 17
源代码 18
1 引 言
哈夫曼的编码和解码对于信息的存储有着重要的作用,同样可以用于通信过程中信息的保密,根据此次设计的程序可以对输入的动态字符进行编码和解码,实现信息的压缩和解压缩功能,对信息的保密有着重要作用。
1.2 研究内容
本次课程设计通过建立哈夫曼树,对字符进行编码和解码,对信息加密提供的极大的便利。本此设计使用C语言以数据结构中哈夫曼树的建立,编码,解码为核心算法,实现了对于信息的压缩与解压缩的功能。
1.3 国内外先进算法动态
构建哈夫曼树:根据给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小的树称为哈夫曼树。从给定的叶子节点中选择两个权值最小的开始建树,生成双亲结点,权值越大结点层次越靠上,生成的树就是哈夫曼树。
哈夫曼压缩算法:生成哈夫曼树之后,从根节点出发,左0右1,根据叶子结点位置生成哈夫曼编码,将每个编码对应结点中的字符,即为哈夫曼编码。
哈夫曼解压缩算法:读取二进制的哈夫曼编码,从根节点开始遍历哈夫曼树,根据读取的字符判断去往左子树还是右子树,读取完一行字符,开始查询对应结点对应的字符,即为哈夫曼解码过程。
撰写人
2 课题分析
编写一个《哈夫曼编码/解码器》的C程序,包括以下功能:
1)将权值数据存放在数据文件(文件名为data.txt,位于执行程序的当前目录中)
2)分别采用动态和静态存储结构
3)初始化:键盘输入字符集大小n、n个字符和n个权值,建立哈夫曼树;
4)编码:利用建好的哈夫曼树生成哈夫曼编码;
5)输出编码;
6)实现译码功能:即随机输入一组字符,实现编码,并能够根据编好的码翻译成输入的字符。
撰写人:
本课题使用最有二叉树即哈夫曼树来实现哈夫曼便阿门译码器的功能。假设输入了n个字符作为哈夫曼树的叶子结点,那么哈夫曼树中的总结点个数就是2n-1个,根据输入的每个字符对应的权值大小(根据权值大的字符在上面,权值小的字符在下面)建立哈弗树。
哈夫曼树每个结点可能存在左右孩子结点,左孩子的编码为0,有孩子的编码为1,通过从根节点遍历哈夫曼树,对每个叶子节点中对应的字符进行编码。解码时通过判断二进制数中的0或1查找叶子节点中的字符。
本课题采用了两种不同的编码解码方式,用户在建立哈夫曼树后,可以选择从键盘输入字符进行哈夫曼编码解码或者直接从文件中读取字符进行编码和解码并存储到文件中等两种实验方式。同时,可以将建立的哈夫曼树进行横向打印,输出到屏幕上。
本程序共3个模块,分别如下:
概要设计结构图(Structure Chart)如下:
//哈夫曼树结点的结构
typedef struct{
char ch;
int weight;
int parent,lchild,rchild;
}HTNode, * HuffmanTree; //动态分配数组存储哈夫曼树
typedef char **HuffmanCode; //动态分配存储哈夫曼编码表
撰写人:
程序基本流程图:
3.3重要数据结构和变量说明
typedef struct{
char ch;
int weight;
int parent,lchild,rchild;
}HTNode, * HuffmanTree; //动态分配数组存储哈夫曼树
typedef char **HuffmanCode; //动态分配存储哈夫曼编码表
HC=(char **)malloc((n+1)*sizeof(char*)); //0空间未用
HT=(HuffmanTree)malloc((2*n+1+1)*sizeof(HTNode));//0空间未用
//建立哈夫曼树
select(HT, i - 1, &x, &y);
HT[x].parent = i;
HT[y].parent = i;
HT[i].lchild = x;
HT[i].rchild = y;
HT[i].weight = HT[x].weight + HT[y].weight;
//--- 从叶子到根逆向求每个字符的哈夫曼编码 ---
cd = (char *)malloc(n*sizeof(char)); // 分配求编码的工作空间
cd[n-1] = '\0'; // 编码结束符
for (i=1; i<=n; ++i) { // 逐个字符求哈夫曼编码
start = n-1; // 编码结束符位置
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]); // 从cd复制编码(串)到HC
}
//从数组开始到结尾进行哈夫曼解码
if (ch == '0') //‘0’判断左走
i = hfmTree[i].lchild;
else if (ch == '1') //‘1’判断右走
i = hfmTree[i].rchild;
if (hfmTree[i].lchild == 0 || hfmTree[i].rchild == 0)
//从根结点一直找到叶子
{
ToBeTran[ct++] = hfmTree[i].ch;
//把i中对应的字符赋值
i = 2 * n - 1; //译完一段编码后置为头结点继续翻译
}
系统流程图,首先我们要进行初始化建立一个哈夫曼树,输入哈夫曼树的信息,然后进行哈夫曼的编码和解码,完成后可以回到主程序中,然后选择进行文件的压缩或者解压缩,也可以将建立的哈夫曼树打印出来。
开始
文件编码 文件解码
是
输入字符编码
输入字符解码
打印树
结束
图3.1 程序整体流程图
图3.2为建树流程图。首先我们输入叶子节点个数,然后提示输入叶子结点的字符和权值,如果输入错误则提示重新输入,根据输入信息生成哈夫曼树。如下图所示:
撰写人:
图4.1为初始界面,当我们运行程序的时候,首先显示课题信息和小组成员,可以点击任意键让程序运行下一步。如下图所示:
图4.1 初始界面
图4.2为使用程序的欢迎界面。如下图所示:
图4.2 欢迎界面
图4.3为该程序的主界面和功能显示,可以根据提示选择本程序的具体功能。如下图所示:
图4.3 主界面图
图4.4为建立哈夫曼树之后,将哈夫曼树横向打印出来,输出到屏幕上。如下图所示:
图4.4 打印哈夫曼树图
撰写人:
哈夫曼树作为对于信息的存储,有着重要的意义。使用软件时,首先我们要进行初始化建立一个哈夫曼树,输入哈夫曼树的信息,然后进行哈夫曼的编码和解码,完成后可以回到主程序中,然后选择进行文件的压缩或者解压缩,也可以将建立的哈夫曼树印出来。
图5.1 程序初始界面图
下图5.2是程序运行过程中的截图,但我们输入叶子结点为3的时候,输入叶子节点对应的字符并且输入权值,生成哈夫曼树。
图5.2 建立哈夫曼树过程图
图5.3是在建立哈夫曼树后对从键盘上输入的字符进行编码和解码,并且将编码解码后的信息输出到屏幕上。
图5.3 动态编码解码图
图5.4是从文件中读取静态存储的字符,进行编码,将编码后的信息打印到屏幕上,并且将储存信息的文本和保存编码信息的文本打开。
图5.4文本静态编码
图5.5是将编码后存入文件中的文本读取出来,根据哈夫曼树进行解码,并且将及我妈后的信息打印到屏幕上,同时打开解码后存入文本中的txt文件。
图5.5文本静态解码
撰写人:
课程设计是培养学生综合运用所学知识 ,发现,提出,分析和解决实际问题,锻炼实践能力的重要环节,是对我们的实际工作能力的具体训练和考察过程.随着科学技术发展的日新月异,当今计算机应用在生活中可以说得是无处不在。因此作为二十一世纪的大学来说掌握程序开发技术是十分重要的,而C语言又是最常见,功能最强大的一种高级语言,因此做好C语言课程设计是十分必要的。回顾起此次课程设计,至今我们仍感慨颇多,的确,自从拿到题目到完成整个编程,从理论到实践,在整整半个月的日子里,可以学到很多很多的东西,同时不仅可以巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。
通过这次课程设计使我们懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。在设计的过程中遇到问题,可以说得是困难重重,这毕竟第一次做的,难免会遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对一些前面学过的知识理解得不够深刻,掌握得不够牢固,比如说结构体,指针,二叉树……通过这次课程设计之后,我们把前面所学过的知识又重新温故了一遍。
我们做的是哈夫曼编码/译码器课程设计,虽然是很简单的一个小的程序,但对我们初次接触算法的学生而言还是有一定难度的。因为是第一次做课程设计,所以第一天下午在机房做了一个下午却丝毫没有进展,最主要是不知从何开始,这个时候才知道上课老师们不厌其烦的教导是多么的宝贵,这个时候才后悔上课的时候没有认真的听讲。可是现在一切都晚了,还好时间还算是充裕,只好拿出书本重新复习一下。
特别是结构体,绘制棋盘的部分,几乎是一片空白,不知从何着手。不过经过几天的努力,大体上把课本上的知识点看了一遍,知识点也都基本是撑握了,所以一下一步就是开始正式的编程序了。不过毕竟是个新手,还是不知如何下手,于是就在网上下了一篇类似的程序,经过仔细的研究,终于读懂了C语言编程的基本过程和方法。经过一波三折,终于开始正式编程。
编程是一件很枯燥很无聊的事情,但是出于完成作业,得到学分的压力,还必须强破自己坚持下去,按照老师所说的模块化思想,分部分的进行编写。而且编程是一件高精度、模范化的事情,稍有疏乎都会影响全局,也可能因为某一处的小的错误而导致整个程序的无法运行。所以认真仔细就是非常重要的了。
开始的时候真的感觉编程是一件很无聊的事情,不过当一个程序运行成功的时候那种喜悦是无法言语的,那种成就感是无法比拟的。又经过几天的努力,终于把程序完成了,尽管程序还是有很多错误和漏洞,不过还是很高兴的。无论如何是自己的劳动成果,是自己经过努力得到的成绩,同时也是学习C语言的一次实践作业,自己进步的证明。
通过这次课程设计,使我对C语言有了更进一步的认识和了解,要想学好它要重在实践,要通过不断的上机操作才能更好地学习它,我也发现我的好多不足之处,首先是自己在指法上还不行,经常按错字母,通过学习也有所改进;再有对C语言的一些标准库函数不太了解,还有对函数调用的正确使用不够熟悉,还有对C语言中经常出现的错误也不了解,通过实践的学习,我认识到学好计算机要重视实践操作,不仅仅是学习C语言,还是其它的语言,以及其它的计算机方面的知识都要重在实践,所以后在学习过程中,我会更加注视实践操作,使自己便好地学好计算机。
在课程设计过程中,收获知识,提高能力的同时,我也学到了很多人生的哲理,懂得怎么样去制定计划,怎么样去实现这个计划,并掌握了在执行过程中怎么样去克服心理上的不良情绪。因此在以后的生活和学习的过程中,我一定会把课程设计的精神带到生活中,不畏艰难,勇往直前!
撰写人:
[1] 谭浩强.《C程序设计(第三版)》,清华大学出版社,2005.7
[2] 郭翠英.《C语言课程设计案例精编》, 中国水利水电出版社,2004.3
[3] 严蔚敏.《数据结构(C语言版)》,清华大学出版社,2004.2
[4] 张翔.《C语言函数大全》,电子工业出版社,2002.4
[5] 徐金梧.《TURBO C实用大全》,机械工业出版社,1996.5
/** 哈夫曼编码译码器**/
#include
#include
#include
#include
#include
//#include
//哈夫曼树结点的结构
typedef struct{
char ch;
int weight;
int parent,lchild,rchild;
}HTNode, * HuffmanTree; //动态分配数组存储哈夫曼树
typedef char **HuffmanCode; //动态分配叔叔存储哈夫曼编码表
// 显示菜单
void Menu();
void color(int x);
void gotoxy(int a,int b);
void HuffmanCoding(HuffmanTree &HT, char *charcater,int* w,int n);//建立哈夫曼树
void select(HuffmanTree HT,int j,int *x,int *y); //从建好的树中选两个最小的结点
void Init(); //初始化哈夫曼
void Coding();// 文件编码
void Decoding();// 文件译码
void Print_tree(); //打印哈夫曼树
void printfht(int root,int height);
int Read_tree(HuffmanTree &x);//从文件中读入哈夫曼树
void Decode(HuffmanTree &,char *ToBeTran, int n);
void Encode(HuffmanTree &,HuffmanCode,int);
HuffmanTree HT; //全局变量
int n = 0; //全局变量,存放哈夫曼树叶子结点的数目
int Decodeflag=0;
void first(){ //登陆界面
color(2);
gotoxy(35,8);
printf("哈夫曼编码/译码器3.0");
color(3);
gotoxy(38,14);
printf("制作人: **********");
}
//自定义函根据参数改变颜色
void color(int x)
{
if(x>=0 && x<=15)//参数在0-15的范围颜色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x); //只有一个参数,改变字体颜色
else//默认的颜色白色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
/************调用函数设置光标位置 ***************/
void gotoxy(int a,int b){
int xx = 0x0b;
HANDLE hOutput;
COORD loc;
loc.X = a;
loc.Y = b;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输出的句柄
SetConsoleCursorPosition(hOutput, loc);//设置光标位置
return;
}
void head()//标题显示
{ color(10);
// gotoxy(20,20);
printf("\t\t\t***********************************************\n");
printf("\t\t\t***********************************************\n");
printf("\t\t\t 欢迎使用哈夫曼编码/译码器\n");
printf("\t\t\t************************************************\n");
printf("\t\t\t************************************************\n");
}
/*********************设置人员滚动字幕****************************/
void gun(){
{
char str[] = "*************";//16
int i = 0,j = 0,k = 0,len = 0;
len = strlen(str);
for(i = 0; i < len;i++)
{
k++;
Sleep(200);
printf("%c",str[i]);
if(i == len-1)
{
Sleep(200);
for(j = 0; j < strlen(str); j++)
printf("\b");
for(j=0;j { putchar(' '); } i = -1; } if( k == 79) { for(j = 0; j < strlen(str); j++) printf("\b"); for(j=0;j { putchar(' '); } printf("\r"); k = 0; i=-1; } } } } /********************************操作选择界面*********************************/ void Menu() { head(); color(12); printf("本系统操作功能如下:\n"); printf(" \t\t-----------------------------------------------------\n"); printf(" \t\t-- 请选择操作 --\n"); printf(" \t\t-----------------------------------------------------\n"); printf(" \n"); printf(" \t\t*1---------------初始化赫夫曼树 ---------------\n"); printf(" \t\t*2---------------文件编码 ---------------\n"); printf(" \t\t*3---------------文件译码 ---------------\n"); printf(" \t\t*4---------------打印树 ---------------\n"); printf(" \t\t*0---------------退出 ---------------\n"); printf(" -----------------------------------------------------\n"); printf("请选择你要进行的操作:\n"); } int main() { char select; first(); getch(); system("cls"); head(); gotoxy(25,25); printf("请点击任意键继续使用。。。"); getch(); system("cls"); while (1) { Menu(); scanf("%c", &select); switch (select) //选择操作,根据不同的序号选择不同的操作 { case '1': system("cls"); Init();//初始化哈夫曼树 break; case '2': printf("请往文本中输入要编码的字符串!(编码根据文本XX的哈夫曼树!)\n"); system("cmd /c start 要编码的文件.txt"); Coding(); system("cmd /c start 编码完的文件.txt"); break; case '3': printf("请往文本中输入要译码的字码!(译码编码完的文件)\n"); system("cmd /c start 编码完的文件.txt"); Decoding(); system("cmd /c start 译码完的文件.txt"); break; case '4': Print_tree(); getch(); system("cls"); break; case '0': system("cls"); color(13); gotoxy(25,25); printf("欢迎下次使用,再见!!!!!!"); exit(1); default: printf("Input error!(输入数字有误,请重新输入))\n"); } getchar(); } return 0; } //建立一个输入条纹的函数 void printLine() { printf("\n---------------------------------------\n"); } //初始化函数,输入n个字符及其对应的权值,根据权值建立哈夫曼树,并将其存于文件hfmtree中 void Init() { FILE *fp; int i, n, w[256]; //数组存放字符的权值 char character[256]; //存放n个字符 system("cls"); head(); printf("\n输入字符个数:"); scanf("%d", &n); //输入字符集大小 printf("请您按提示输入每种字符以及其对应的权值:\n"); printLine(); getch(); for (i = 0; i { char b = getchar(); printf("请您输入第%d个字符:\n",i+1); scanf("%c", &character[i]); printf("请输入该字符对应的权值:\n"); scanf("%d", &w[i]); //输入n个字符和对应的权值 printLine(); } printf("\n\n字符集为:\n"); for(int i=0;i { printf("%c:\t%d\n",character[i],w[i]); //将字符和权值打印出来 } HuffmanCoding(HT, character, w, n); //建立赫夫曼树 printf("下面将输入的字符的哈夫曼编码写入文件hfmtree.txt文件中\n"); if ((fp = fopen("hfmtree.txt", "w")) == NULL) printf("Open file hfmtree.txt error!(打开hfmtree.txt文件错误)\n"); // fprintf(fp, "%s\t\t%s\t\t%s\t\t%s\t\t%s\t\t%s\n", "单元号", "字符", "权值", "双亲", "左孩子", "右孩子"); for (i = 1; i <= 2 * n - 1; i++) { fprintf(fp, "%d %c %d %d %d %d\n", i, HT[i].ch, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild); //将建立的赫夫曼树存入文件hfmtree.txt中 } printf("\n赫夫曼树建立成功,并已存于文件hfmtree.txt中\n"); fclose(fp); gotoxy(60,40); printf("请点击任意键继续..."); getch(); system("cls"); //Menu(); Decodeflag=1; char *ToBeTran; HuffmanCode HC; char ch; //while(scanf("%c",&ch)!=EOF) // getch(); color(8); printf("点击回车查看字符集编码结果:\n"); getch(); // select2=getchar(); //判断是否进行编码/解码测试 while(1) { scanf("%c",&ch); if(ch!='*') //输入*号跳出测试循环 { Encode(HT,HC,n); //调用编码函数 Decode(HT,ToBeTran,n); //调用解码函数 } else break; //Menu(); } printf("\n"); printf("\n"); printf("\n"); } //构造哈夫曼树的算法 void HuffmanCoding(HuffmanTree &HT, char *character, int * w, int n) { //w存放n个字符的权值(均>0),构造哈夫曼树HT int m, i, x, y; HuffmanTree p; if (n <= 1) return; m = 2 * n - 1; HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); for (p = HT + 1, i = 1; i <= n; ++i, ++p, ++character, ++w) { p->ch = *character; p->weight = *w; p->parent = 0; p->lchild = 0; p->rchild = 0; } for (; i <= m; ++i, ++p) { p->ch = 0; p->weight = 0; p->parent = 0; p->lchild = 0; p->rchild = 0; } for (i = n + 1; i <= m; ++i) { select(HT, i - 1, &x, &y); HT[x].parent = i; HT[y].parent = i; HT[i].lchild = x; HT[i].rchild = y; HT[i].weight = HT[x].weight + HT[y].weight; } } //从HT[1]到HT[j]中选择parent为0,weight最小的两个结点,用x和y返回其序号 void select(HuffmanTree HT, int j, int *x, int *y) { int i; //int minwight=65535; //查找weight最小的结点 for (i = 1; i <= j; i++) if (HT[i].parent == 0) { *x = i; break; } for (; i <= j; i++) if ((HT[i].parent == 0) && (HT[i].weight *x = i; HT[*x].parent = 1; //查找weight次小的结点 for (i = 1; i <= j; i++) if (HT[i].parent == 0) { *y = i; break; } for (; i <= j; i++) if ((HT[i].parent == 0) && (i != *x) && (HT[i].weight *y = i; /** for(i=1;i<=j;i++) { if(HT[i].parent == 0&&HT[i].weight { *x=i; minweight=HT[i].weigh; } } HT[*x].parent = 1; for(i=1;i<=j;i++) { if(HT[i].parent == 0&&HT[i].weight { *y=i; minweight=HT[i].weigh; } } HT[*y].parent = 1; **/ } //对文件正文进行编码,然后将结果存入另一个文件中 void Coding() { FILE *fp, *fw; int i, f, c, start,r; char *cd; HuffmanCode HC; n = Read_tree(HT);//从文件hfmtree.txt中读入赫夫曼树,返回叶子结点数 //求赫夫曼树中各叶子节点的字符对应的的编码,并存于HC指向的空间中 { HC = (HuffmanCode)malloc((n + 1) * sizeof(char*)); cd = (char *)malloc(n * sizeof(char)); cd[n - 1] = '\0'; for (i = 1; i <= n; ++i) { start = n - 1; 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)); strcpy(HC[i], &cd[start]); } free(cd); } if ((fp = fopen("要编码的文件.txt", "r")) == NULL) printf("Open file 要编码的文件.txt error!\n"); if ((fw = fopen("编码完的文件.txt", "w")) == NULL) printf("Open file 编码完的文件.txt error!\n"); char temp; while (1) { fscanf(fp, "%c", &temp); printf("%c",temp); if(temp=='#') break; //从文件读入下一个字符 i=1; for (; i <= n; i++) if (HT[i].ch == temp) //在赫夫曼树中查找字符所在的位置 break; for (r = 0; HC[i][r] !='\0'; r++) //将字符对应的编码存入文件 { fputc(HC[i][r], fw); // putchar(HC[i][r]); } } printf("\n"); for(i=1;i<=n;i++) printf("%c的编码是: %s\n",HT[i].ch,HC[i]); printLine(); // gotoxy(30,10); printf("请点击任意键继续:\n"); fclose(fw); fclose(fp); printf("\n已将文件hfmtree.txt成功编码,并已存入编码完的文件.txt中!\n\n"); getch(); system("cls"); // color(5); } //从文件hfmtree.txt中读入赫夫曼树,返回叶子节点数 int Read_tree(HuffmanTree &HT) { FILE *fp; int i, n; HT = (HuffmanTree)malloc(sizeof(HTNode)); if ((fp = fopen("hfmtree.txt", "r")) == NULL) printf("Open file hfmtree.txt error!\n"); for (i = 1;!feof(fp); i++) { HT = (HuffmanTree)realloc(HT, (i + 1) * sizeof(HTNode)); //增加空间 fscanf(fp, "%d %c %d %d %d %d\n",&i,&HT[i].ch,&HT[i].weight,&HT[i].parent,&HT[i].lchild,&HT[i].rchild); } fclose(fp); n = (i + 1) / 2; return n; } //将文件的代码进行译码,结果存入文件textfile中 void Decoding() { FILE *fp, *fw; int m, i,ct=0,j=0; char text[300],ch,str[300]; if (n == 0) n = Read_tree(HT);//从文件hfmtree.txt中读入赫夫曼树,返回叶子结点数 if ((fp = fopen("编码完的文件.txt", "r")) == NULL) printf("Open file 编码完的文件 error!\n"); if ((fw = fopen("译码完的文件.txt", "w")) == NULL) printf("Open file 译码完的文件.txt error!\n"); fscanf(fp, "%s", str); ch=str[0]; printf("%s",str); printf("\n"); m = 2 * n - 1; while(1) { if(ch=='0') m= HT[m].lchild; else m=HT[m].rchild; if (HT[m].lchild ==0&&HT[m].rchild ==0)//从根结点一直找到叶子 { printf("%c",HT[m].ch); text[ct++] = HT[m].ch; m = 2 * n - 1; } j++; ch=str[j]; if(j==strlen(str)) break; } if ((HT[m].lchild !=0|| HT[m].rchild != 0) && m != 2 * n - 1) printf("编码有误!"); text[ct]='\0'; fprintf(fw,"%s",text); fclose(fp); fclose(fw); printf("\n已将编码完的文件成功译码,并且已存入译码完的文件.txt!\n\n"); getch(); system("cls"); } /*********************对键盘上输入的字符进行解码 ************************/ // void Decode(HuffmanTree &hfmTree,char *ToBeTran, int n) { int i,ct=0; char ch; printLine(); printf("接下来,根据哈夫曼树进行译码的测试:\n"); printf("输入需要二进制译文的编码(以#号结束):\n"); scanf("%c", &ch); i = 2 * n - 1;//根结点的下标(地址)为2*N-2 while (ch!='#')//#结束后不再翻译 { if (ch == '0') //‘0’判断左走 i = hfmTree[i].lchild; else if (ch == '1') //‘1’判断右走 i = hfmTree[i].rchild; if (hfmTree[i].lchild == 0 || hfmTree[i].rchild == 0) //从根结点一直找到叶子 { ToBeTran[ct++] = hfmTree[i].ch; //把i中对应的字符赋值给 i = 2 * n - 1; //译完一段编码后置为头结点继续翻译 } scanf("%c", &ch); } if ((hfmTree[i].lchild != 0 || hfmTree[i].rchild != 0) && i != 2 * n- 1) printf("编码有误!"); ToBeTran[ct] = '\0'; printf("\n"); printf("编码译文为:\n"); printf("%s\n", ToBeTran); getch(); system("cls"); } /*************哈夫曼进行编码*******************/ void Encode(HuffmanTree &,HuffmanCode HC,int n) { static int flag=0; int i, f, c, start,r,j; char *cd,str[200]; { HC = (HuffmanCode)malloc((n + 1) * sizeof(char*)); cd = (char *)malloc(n * sizeof(char)); cd[n - 1] = '\0'; for (i = 1; i <= n; ++i) { start = n - 1; 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)); strcpy(HC[i], &cd[start]); } free(cd); } printf("\n"); if(flag==0) color(15); for(i=1;i<=n;i++) printf("%c的编码是: %s\n",HT[i].ch,HC[i]); getch(); system("cls"); color(9); printf("接下来根据哈夫曼树进行编码测试:\n"); gotoxy(30,10); printf("请点击任意键继续。。。\n"); getch(); system("cls"); flag++; printf("请输入需要编码的字符串:\n"); scanf("%s",str); printf("该字符串编码为:\n"); for (i = 0;i { for(j=1;j<=n;j++) if(str[i]==HT[j].ch) { flag=j; break; } printf("%s",HC[flag]); } printf("\n"); } // 打印哈夫曼树 void Print_tree() { n = Read_tree(HT); printfht(2*n-1,n); } void printfht(int root,int height) { int m,i; n = Read_tree(HT); if(root) { printfht(HT[root].rchild,height+1); for(i=0;i printf("\t"); printf("%d",HT[root].weight); if(HT[root].lchild==0&&HT[root].rchild==0) printf("\\\\%c",HT[root].ch); else printf("<"); printf("\n"); printfht(HT[root].lchild,height+1); } // getch(); // system("cls"); } 课设题目 哈夫曼编码/译码器 姓名 学号 成绩 姓名 学号 成绩 姓名 学号 成绩 组长评价: 本次课题的研究,我们小组都收获颇丰,我们小组分工合作、齐心协力,一齐完成了课程设计前的准备工作。课程设计这样群众的任务光靠团队里的一个人或几个人是不可能完成好的,合作的原则就是要利益均沾,职责公担。如果让任务交给一个人,那样既增加了他的压力,也增大了完成任务的风险,降低了工作的效率。虽然课程设计结束了,但我们一齐奋斗的精神和这份宝贵的经历将会成为人生道路上一道亮丽的风景线。 教师评语: 教师签名: 年 月 日