课程设计哈弗曼编码译码器
哈夫曼编码译码器

沈阳航空航天大学课程设计报告课程设计名称:数据结构课程设计课程设计题目:哈夫曼编码/译码器院(系):计算机学院专业:计算机科学与技术班级:学号:姓名:指导教师:沈阳航空航天大学课程设计报告目录沈阳航空航天大学 (I)第1章概要设计 (1)1.1题目的内容与要求 (1)1.2总体结构 (1)第2章算法分析 (2)2.1核心算法思想 (2)2.2算法结构定义 (2)第3章详细设计 (3)3.1功能流程 (3)第4章系统实现 (5)4.1错误分析 (5)4.2运行结果 (5)参考文献 (8)附录 (9)沈阳航空航天大学课程设计报告第1章概要设计1.1题目的内容与要求内容:设计一个利用哈夫曼算法的编码和译码系统,可以接收从键盘输入的字符集大小、字符和权值信息,创建哈夫曼树生成哈夫曼编码并能对其进行解码。
要求:1.存储结构自定;2.将生成的哈夫曼编码与等长编码进行比较,判断优劣;3.给出动态演示过程(选作)。
1.2总体结构本程序主要分为3个模块(功能模块图见图1.1):主模块,编码模块,译码模块。
主模块:程序的主体部分,分别调用各个模块,实现各项功能。
编码模块:对每个出现的字符进行编码。
译码模块:将已有编码译成字符,使之可以直接被读出。
图1.1功能模块图沈阳航空航天大学课程设计报告第2章算法分析2.1核心算法思想哈夫曼树的建立由赫夫曼算法的定义可知,初始森林中共有n棵只含有根结点的二叉树。
算法的第二步是:将当前森林中的两棵根结点权值最小的二叉树,合并成一棵新的二叉树;每合并一次,森林中就减少一棵树,产生一个新结点。
显然要进行n-1次合并,所以共产生n-1个新结点,它们都是具有两个孩子的分支结点。
由此可知,最终求得的哈夫曼树中一共有2n-1个结点,其中n个结点是初始森林的n个孤立结点。
并且哈夫曼树中没有度数为1的分支结点。
我们可以利用一个大小为2n--1的一维数组来存储哈夫曼树中的结点。
哈夫曼编码是可变字长编码。
哈夫曼编码译码器课程设计

哈夫曼编码译码器课程设计1.哈夫曼编码是一种有效的数据压缩算法,通过将最常用的字符编码为较短的比特串,最大限度地减少了存储空间。
本文档介绍一个哈夫曼编码译码器的设计和实现,该译码器可以实现从原始文本到哈夫曼编码的转换,并且可以从哈夫曼编码还原出原始文本。
2. 设计和实现本译码器的开发采用Python语言,主要分为两部分:哈夫曼编码和译码两部分。
2.1 哈夫曼编码哈夫曼编码的过程主要分为两步:1.统计每个字符出现的频率,并生成一个频率表。
2.根据频率表生成哈夫曼树,并生成相应的编码表。
以下是用于生成哈夫曼编码的Python代码:import heapqfrom collections import defaultdictclass Node:def__init__(self, freq, char=None, left=None, right=None): self.freq = freqself.char = charself.left = leftself.right = rightdef__lt__(self, other):return self.freq < other.freqdef__eq__(self, other):return self.freq == other.freqdef build_tree(data):freq = defaultdict(int)for char in data:freq[char] +=1q = [Node(freq[char], char) for char in freq]heapq.heapify(q)while len(q) >1:left = heapq.heappop(q)right = heapq.heappop(q)parent = Node(left.freq + right.freq, left.char + right.char, l eft, right)heapq.heappush(q, parent)return q[0]def generate_codes(node, current_code='', codes={}):if node is None:returnif node.char is not None:codes[node.char] = current_codegenerate_codes(node.left, current_code +'0', codes)generate_codes(node.right, current_code +'1', codes)return codes通过调用build_tree()函数来生成哈夫曼树,并调用generate_codes()函数来生成编码表。
数据结构课程设计 哈夫曼编码与译码器课程设计

数据结构课程设计题目名称:哈夫曼编码与译码器课程设计计算机科学与技术学院1.需求分析(1)熟练掌握哈夫曼编译原理(2)掌握程序设计步骤(3)根据哈夫曼编码原理,设计一个程序,在已知相关字符和字符对应权值(文件中存在或者用户输入)的情况下,根据用户要求对相应内容进行编码、译码等相应操作。
(4)输入的形式和输入值的范围;(5) 输出的形式;(6) 程序所能达到的功能;(7) 测试数据:包括正确的输入及其输出结果和含有错误的输入及其输出结果2.概要设计1.写好流程图,设计实验方案。
2.初始化,从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件HuofumanTree中。
3.编码。
利用已建好的哈夫曼树,对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
4.译码。
利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。
5.印代码文件(Print)将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrint中。
6.印哈夫曼树(Treeprinting).将已在内存中的哈夫曼树以直观的方式(比如树)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
具体函数如下:1.Initialization()初始化2.Encoding()编码3.Decoding()译码4.Print_file()打印代码文件5.search(k,j,p)搜索二叉树6.Print_tree() 打印二叉树7.menu()主菜单8.main()主函数3.详细设计(1)哈夫曼结点定义类型以一个节点为单位,其中节点中包括他的父亲·左孩子·右孩子,权值(2)存储字符信息(3)用于编码时存取字符长度及起始位置(4)初始化将数据存入文件中void Initialization(){int i,j;FILE* HFM_f;//定义一个指针指向文件HFM_f = fopen("C:/Users/lenovo/Desktop/x.txt","w");//将文件打开,赋值给HFM_fif(HFM_f == NULL){printf("create file error!\n");}printf(" 请输入字符集大小: ");scanf("%d",&leaves);fprintf(HFM_f,"----输入的值-----\n");fprintf(HFM_f," 字符大小%4d\n",leaves);fprintf(HFM_f," 字符权值\n");for(i=0; i<leaves; i++){printf(" 请输入第%d个字符和其权:",i+1);scanf(" %c ",&HFM_num[i].hfstr);scanf("%d",&HFM_num[i].weight);fprintf(HFM_f,"%4c",HFM_num[i].hfstr);fprintf(HFM_f,"%4d\n",HFM_num[i].weight); //存储字符和权值}(5)建立哈夫曼树for(i=0; i<maxsize; i++)//哈夫曼树初始化{HFM_tree[i].parent = -1;HFM_tree[i].lchild = -1;HFM_tree[i].rchild = -1;HFM_tree[i].weight = 0;}for(i=0; i<leaves; i++){HFM_tree[i].weight = HFM_num[i].weight;}for(i=0; i<leaves-1; i++){int m1,m2;int m1_pos,m2_pos;m1=m2=65536;m1_pos=m2_pos=0;for(j=0; j<leaves+i; j++)//选出最小且没被访问的两个数{if(HFM_tree[j].weight<m1&&HFM_tree[j].parent == -1) {m2 = m1;m1 = HFM_tree[j].weight;m2_pos = m1_pos;m1_pos = j;}else{if(HFM_tree[j].weight<m2&&HFM_tree[j].parent == -1){m2 = HFM_tree[j].weight;m2_pos = j;}}}HFM_tree[leaves+i].parent = -1;HFM_tree[leaves+i].lchild = m1_pos;//HFM_tree[leaves+i]为两者的最小和的结点,即他们的父亲HFM_tree[leaves+i].rchild = m2_pos;HFM_tree[m1_pos].parent = leaves+i;HFM_tree[m2_pos].parent = leaves+i;HFM_tree[leaves+i].weight = m2+m1;//将和赋为他们的父亲结点的权值}(6)输出哈夫曼树printf("----------------哈夫曼编码--------------\n");printf(" parent lchild rchild weight\n");fprintf(HFM_f,"-------------哈夫曼编码------------\n");fprintf(HFM_f," parent lchild rchild weight\n");for(i=0; i<leaves*2-1; i++){printf("%8d%8d%8d%8d\n",HFM_tree[i].parent,HFM_tree[i].lchild,HFM_tre e[i].rchild,HFM_tree[i].weight);fprintf(HFM_f,"%8d%8d%8d%8d\n",HFM_tree[i].parent,HFM_tree[i].lchild, HFM_tree[i].rchild,HFM_tree[i].weight);}printf("\n");fclose(HFM_f);//关上文件}(7)编码void Encoding(){int i,j,p,c,k;FILE* HFM_f = fopen("CodeFile.txt","w");//打开文件if(HFM_f == NULL){printf("open file error!\n");}for(i=0; i<leaves; i++){c = i;//当前结点编号p = HFM_tree[i].parent;//父亲结点编号HFM_hf.start = len-1;//单个结点路径长度-1,即循环次数,从0开始算while(p!=-1)//根节点的p=-1,即根结点的父亲值为-1,即为初始化的值,证明根节点没有父亲结点{if(HFM_tree[p].lchild == c)//若左孩子为C,赋值0{HFM_hf.bit[HFM_hf.start] = 0;}else{HFM_hf.bit[HFM_hf.start] = 1;//若右孩子为c,赋值1 }--HFM_hf.start;c = p;//沿着树往上走,将刚才的父亲变为孩子p = HFM_tree[c].parent;//寻找当前结点的父亲,即原节点的爷爷}for(j=HFM_hf.start+1,k=0; j<len; j++,k++){HFM_code[i].bit[k] = HFM_hf.bit[j];}HFM_code[i].length = len-HFM_hf.start-1;HFM_code[i].start = HFM_hf.start+1;}for(i=0; i<leaves; i++){HFM_code[i].hfch = HFM_num[i].hfstr;printf(" character:%c start:%d length:%dCode:",HFM_code[i].hfch,HFM_code[i].start,HFM_code[i].length );for(j=0; j<HFM_code[i].length; j++){printf("%d",HFM_code[i].bit[j]);fprintf(HFM_f,"%d",HFM_code[i].bit[j]);}printf("\n");}printf("\n");fclose(HFM_f);}4.调试结果输入26个字符及其权值26个字母的编码如下:译码如下:打印文件中的内容:打印出的哈夫曼树如下:5.时间复杂度本代码的哈夫曼算法的时间复杂度为O(n^3)。
哈夫曼编码译码器课程设计

学年设计报告设计题目哈夫曼树的建立与实现作者姓名所学专业网络工程指导教师学年设计任务书目录1 引言 (4)2 需求分析 (4)3 概要设计 (4)3.1设计思路及方案 (4)3.2模块的设计及介绍 (4)4 详细设计 (8)4.1主调函数 (8)4.2建立H UFFMAN T REE (9)4.3生成H UFFMAN树并写入文件 (10)5 调试与操作说明 (11)5.1读出文本 (11)5.2输出哈夫曼树存储结构的初态 (12)5.3输出哈夫曼树存储结构的终态 (12)5.4输出哈夫曼树构成后的抽象图 (14)6学年设计总结与体会 (14)7 参考文献 (15)8 致谢 (15)9 附录 (15)学年设计的主要内容1 引言随着当今信息技术的发展,为了方便和节省信息的存储和传递速度,人们便创建了哈夫曼编码。
哈夫曼编码是将文件进行压缩的一种压缩方法。
哈夫曼编码的最大的功能是能够用更少的内存空间来存储更多的信息。
若要对文件进行编码则必须对其建立哈夫曼树,其次对这个哈夫曼树进行编码。
本学年设计的主要目标就是对如何建立哈夫曼树和如何进行编码的一个详细介绍。
2 需求分析问题描述:打开一篇英文文章,统计该文章中每个字符出现的次数,然后以它作为权值,对所有字符进行构建哈夫曼树。
问题补充:⑴从硬盘的一个文件里读出一段英语文章;⑵统计这篇文章中的每个字符出现的次数;⑶以字符出现字数作为权值,构建哈夫曼树,并将哈夫曼树的存储结构的初态和终态进行输出。
具体介绍:在E盘中预先建立一个filel.txt文档,在文档中编辑一篇文章(大写)。
然后运行程序,调用fileopen()函数读出该文章,显示在界面;再调用jsq()函数对该文章的字符种类进行统计,并对每个字符的出现次数进行统计,并且在界面上显示;然后以每个字符出现次数作为权值,调用ChuffmanTree()函数构建哈夫曼树,并调用print1()和print2()函数将哈夫曼的存储结构的初态和终态进行输出。
数据结构课程设计哈夫曼编码实验

数据结构设计性实验Huffman编码与译码学号姓名班级设计性实验—Huffman 编码与译码一.实验目的:在掌握相关基础知识的基础上,学会自己设计实验算法,熟练掌握Huffman 树的建立方法,Huffman 编码的方法,进而设计出Huffman 译码算法,并编程实现。
二.实验要求:在6学时以内,制作出能够实现基于26个英文字母的任意字符串的编译码。
写出技术工作报告并附源程序。
三.实验内容及任务:1.设字符集为26个英文字母,其出现频度如下表所示。
2.建Huffman 树; 3.利用所建Huffman 树对任一字符串文件进行编码——即设计一个Huffman 编码器;4.对任一字符串文件的编码进行译码——即设计一个Huffman 译码器。
实现步骤:1.数据存储结构设计; 2.操作模块设计; 3.建树算法设计; 4.编码器设计;5. 译码器设计;51 48 1 15 63 57 20 32 5 1频度z y x w v u t 字符11611882380频度p 21 f q15 g r 47 h s o n m l k j 字符 57 103 32 22 13 64 186 频度 i e d c b a 空格 字符四.分析以及算法描述1.分析问题1)首先学习二叉树的知识,了解二叉树的路径、权数以及带权路径长度计算。
2)认识霍夫曼树,了解霍夫曼树的定义,构造霍夫曼树构造算法①又给定的n个权值{w1,w2,w3,……,w n}构造根节点的二叉树,从而得到一个二叉树森林F={T1,T2,T3,……T n}。
②在二叉树森里选取根节点全职最小和此最小的两棵二叉树作为左右节点构造新的二叉树,此时新的二叉树的根节点权值为左右子树权值之和。
③在二叉树森林中删除作为新二叉树的根节点左右子树的两棵二叉树,将新的二叉树加入到二叉树森林F中。
④重复②和③,当二叉树森林F只剩下一棵二叉树时,这棵二叉树是所构造的霍夫曼树。
3)练习通过普通树来构造霍夫曼树。
课程设计哈夫曼编码

《数据结构》课程设计报告设计题目哈夫曼(Huffman)编译码器学院名称信息工程学院专业班级 13计本1 姓名 hhh学号1312219999目录一、实验题目-哈夫曼(Huffman)编/译码器 ------------------------------二、问题描述-----------------------------------------------三、设计目标-----------------------------------------------四、需求分析-----------------------------------------------五、概要设计-----------------------------------------------1---系统结构图--------------------------------------2--各个模块功能的详细描述------------------------------- 六、详细设计-----------------------------------------------1——详细代码--------------------------------------a)头文件代码--------------------------------------b)主函数代码--------------------------------------2——系统流程图--------------------------------------七、测试分析-----------------------------------------------八、使用说明-----------------------------------------------1、白盒-----------------------------------------------2、黑盒-----------------------------------------------九、课程设计总结----------------------------------------------一、实验题目哈夫曼(Huffman)编/译码器二、问题描述利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
数据结构课程设计哈夫曼编码译码器.doc

数据结构课程设计哈夫曼编码译码器.题目一:哈夫曼编码与译码一、任务设计一个利用哈夫曼算法的编码和译码系统,重复地显示并处理以下项目,直到选择退出为止。
要求:1)将权值数据存放在数据文件(文件名为data.txt,位于执行程序的当前目录中) ;2)初始化:键盘输入字符集统计字符权值、自定义26个字符和26个权值、统计文件中一篇英文文章中26个字母,建立哈夫曼树;3)编码:利用建好的哈夫曼树生成哈夫曼编码;4)输出编码(首先实现屏幕输出,然后实现文件输出);5)译码(键盘接收编码进行译码、文件读入编码进行译码);6)界面优化设计。
二、流程图主菜单1.建立字符权值 2.建立并输出哈夫曼树3.建立并查看哈弗曼编码4.编码与译码0.退出系统1.从键盘输入字符集统计权值2.从文件读入字符集统计权值3.自定义字符及权值0.返回上级菜单输出哈夫曼树并保存至文件“哈夫曼树。
txt”输出哈夫曼编码并保存至文件“哈夫曼编码。
txt1.编码2.译码0.返回上级菜单1.从键盘输入字符集进行编码2.从文件读入字符集进行编码1.从键盘输入编码进行译码 2.从文件读入编码进行译码0.返回上级菜单0.返回上级菜单三、代码分解//头文件#include#include#include#include #define N 1000#define M 2*N-1#define MAXcode 6000//函数声明void count(CHar ch,HTNode ht[]);void editHCode(HTNode ht[],HCode hcd[],CHar ch,int n,char bianma[]); //编码函数void printyima(HTNode ht[],HCode hcd[],int n,char bianma[]); //译码函数void creatHT(HTNode ht[],int n);void CreateHCode (HTNode ht[],HCode hcd[],int n);void DispHCode(HTNode ht[],HCode hcd[],int n);void input_key(CHar ch);void input_file(CHar ch);void input_cw(HTNode ht[]);void bianma1(HTNode ht[],HCode hcd[],CHar ch,int n,char bianma[]);void bianma2(HTNode ht[],HCode hcd[],CHar ch,int n,char bianma[]);void yima1(HTNode ht[],HCode hcd[],int n,char bianma[]);void yima2(HTNode ht[],HCode hcd[],int n,char bianma[]);void creat_cw();void bianmacaidan();void yimacaidan();void bianmayima();int caidan(); //结构体typedef struct-省略部分-;}void bianma2(HTNode ht[],HCode hcd[],CHar ch,int n,char bianma[]){ int i; FILE*fp; char filename[20]; printf("请输入要打开的文件名(*.txt):"); scanf("%s",filename); if((fp=fopen(filename,"r"))==NULL) { printf("\n\t\t文件打开失败!!!"); return; } for(i=0;!feof(fp);i++) { fread(ch.s[i],sizeof(char),1,fp); } ch.num=strlen(ch.s); printf("\n读入成功!\n"); printf("文件中的字符集为:\n%s",ch.s); fclose(fp);editHCode(ht,hcd,ch,n,bianma); getch(); system("cls"); return;}//译码函数void yima1(HTNode ht[],HCode hcd[],int n,char bianma[]){ int i; char code[MAXcode]; printf("请输入编码进行译码(以‘#’结束):\n"); for(i=0;i四、调试结果主菜单建立字符权值选择2.从文件读入字符进行统计输入测试文件名“cs.txt”输出个字符权值建立哈夫曼树并输出至文件生成哈夫曼编码并保存至文件编码选择2.从文件读入字符集编码编码结果保存至文件译码选择2.从文件读入编码,读入上一步的编码译码完成,返回!退出系统word教育资料div ;i++) 达到当天最大量API KEY 超过次数限制。
哈夫曼编码译码器---课程设计报告.docx

目录目⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯ (2)1 程的目的和意⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯32 需求分析⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯43 概要⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯4 4⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯.85 分析和果⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯.11 6⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯127致⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯138附⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯13参考文献⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯..201课程设计目的与意义在当今信息爆炸时代,如何采用有效的数据压缩技术来节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视。
哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。
哈夫曼编码的应用很广泛,利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。
树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“ 1”的序列作为和各个对应的字符的编码,这就是哈夫曼编码。
通常我们把数据压缩的过程称为编码,解压缩的过程称为解码。
电报通信是传递文字的二进制码形式的字符串。
但在信息传递时,总希望总长度尽可能最短,即采用最短码。
作为计算机专业的学生,我们应该很好的掌握这门技术。
在课堂上,我们能过学到许多的理论知识,但我们很少有过自己动手实践的机会!课程设计就是为解决这个问题提供了一个平台。
在课程设计过程中,我们每个人选择一个课题,认真研究,根据课堂讲授内容,借助书本,自己动手实践。
这样不但有助于我们消化课堂所讲解的内容,还可以增强我们的独立思考能力和动手能力;通过编写实验代码和调试运行,我们可以逐步积累调试 C 程序的经验并逐渐培养我们的编程能力、用计算机解决实际问题的能力。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
哈弗曼编码译码器软件121班2012023040王祥袁目录评分表 (2)问题描述 (3)功能分析 (3)系统设计1.数据结构类型 (3)2.主要模块算法描述 (3)3.详细设计 (7)测试 (20)总结 (33)软件工程课程设计评分表班级姓名指导教师题目:评分标准评分标准分数权重评分的依据得分A C工作态度10 态度端正,能主动认真完成各项内容,不迟到早退,出勤好。
能够完成各环节基本工作,出勤较好。
程序设计,完成及运行情况20功能达到设计要求,程序稳定、界面美观、符合规范、程序易读、完成率100%、程序运行正确。
功能实现了大部分,程序较稳定、界面可用性一般、程序有注释、完成率不足70%。
相关文档40 格式规范,层次清晰,设计思想明确,解决问题方法合理,文档编写完整规范,编写过程符合软件工程开发设计流程等。
格式较规范,设计思想基本明确,解决问题方法较合理,基本遵循软件工程开发流程。
答辨问题回答30能准确回答老师提出的问题,并充分理解数据库开发技术,程序逻辑清晰。
能基本准确回答老师提出的问题总分指导教师(签字):注:介于A和C之间为B级,低于C为D级和E级。
按各项指标打分后,总分90~100为优,80~89为良,70~79为中,60~69为及格,60分以下为不及格。
一.问题描述:用电子方式处理符号时,需先对符号进行二进制编码。
例如,在计算机中使用的英文字符的ASCII编码就是8位二进制编码,ASCII编码是一种定长编码,即每一个字符用相同的二进制位编码。
为了提高传输效率及缩短数据文件(报文)长度,可采用不定长编码。
这里就应用到了哈弗曼编码。
那么,如何创建一个哈弗曼树,并能对一篇英文文章进行编码,同时还能对电文进行译码呢?二.功能分析:1、输入的形式和输入值的范围:本演示程序中,字符及相应权值的输入有三种方式:从文件读入、手动输入、由电文随机生成。
电文编码及译码翻译均直接从文件读入,电文内容根据权值有所限定,仅支持英文字符组成的电文,在不支持其他语言组成的电文。
对于菜单的选择,按照菜单提供的选择项进行选择即可,若输出位置菜单项,会提示错误,只需重新输入即可。
2、输出的形式:演示程序以人机交互的方式执行,即在计算机终端上显示“提示信息”之后,由用按需户求在键盘上作相应的选择,哈夫曼树、电文编码及译码均输出到文件,哈夫曼编码输出到屏幕。
3、程序所能达到的功能:(1)多级演示菜单显示(2)创建哈夫曼树(3)从文件读入已有的哈夫曼树(4)查看哈夫曼编码的编码方式(5)对电文进行编码(6)对电文进行译码(5)以上功能的反复进行(6)结束三.系统设计1.所选用的数据结构:采用哈弗曼树的树形存储结构,由于哈弗曼树是具有相同叶字个数的二叉树中带权路径长度最小的二叉树,涉及根据叶子数求其“规模最小”的二叉树问题,用哈弗曼树构造哈弗曼编码是其典型应用。
2.主要模块算法描述:(1)建立哈弗曼树:开始初始化非叶子节点I=huffmanleaf否I<2*huffmanleaf-1!是I++选两个最小权值的结点HufNode[s1].parent=iHufNode[s2].parent=iHufNode[i].lchild=s1HufNode[i].rchild=s2HufNode[i].weight=HufNode[s1].w结束(2)编码: 否是是否否是开始I=0I<叶子数?Start=叶子数-1根节点?左孩子?编码为‘0’编码为‘1’存储编码I++结束(3)译码: 是否否是开始P 指向根节点P 是叶子?读入编码字符是‘0’?P 指向左孩子P 指向右孩子读取叶子结点上的字符结束3.详细设计:(1)元素类型,结点类型和指针类型:#define Statue int#define ElemType char//—————哈夫曼树和哈夫曼编码的存储表示——————typedef struct hnode{char letter; //本身字符信息int weight; //字符的权值int parent,lchild,rchild;//双亲及孩子信息}HuffmanNode; //哈弗曼树节点结构类型定义typedef struct{char letter; //本身字符信息char bit[MAXLEAF];//字符编码int start; //编码长度}HuffmanCode; //哈弗曼编码类型定义//—————哈夫曼树和哈夫曼编码的数组定义——————HuffmanNode HuffNode[2*MAXLEAF-1];//定义全局变量HuffmanCode HuffCode[MAXLEAF];int HuffmanLeaf=0; //叶子节点unsigned long Weight[256]={0};//存储字符权值(2)主程序模块:int main(int argc, char** argv) {HuffmanMenu();return 0;}(3)哈夫曼树建立模块:Huffmantree.hint SaveHuffmanTree() //将已生成的哈夫曼树存到文件{FILE *fp,*p; //文件指针int i;if((p=fopen("hfmantree.txt","w"))==NULL||(fp=fopen("hfmantree.dat","wb"))==NULL)//文件打开失败则直接返回{printf("\n保存失败!\n");return ERROR;}fprintf(p,"letter\tweight\tparent\tlchild\trchild\n");for (i=0;i<2*HuffmanLeaf-1;i++)fprintf(p,"%c\t%d\t%d\t%d\t%d\n",HufNode[i].letter,HufNode[i].weight,HufNode[ i].parent,HufNode[i].lchild,HufNode[i].rchild);//写入txt文件fclose(p);printf("\n成功保存Haffman树到hfmantree.txt!\n"); //写入txt文件成功fwrite(HufNode,sizeof(struct hnode),2*HuffmanLeaf-1,fp); //将哈夫曼树写到dat文件printf("\n成功保存Haffman树到hfmantree.dat!\n"); //写入dat文件成功fclose(fp);//指针释放return OK;}int WriteHuffman() //读取文件中的字符及权值{FILE *fp;ElemType ch,filename[10];int weight,i=0;cout<<"\n请输入所要读入字符及相应权值的文件名(如test.txt):\n";scanf("%s",filename); //可以打开同目录下任意格式的文件fflush(stdin);if ((fp=fopen(filename,"rb"))==NULL) //若打开文件失败,直接返回{printf("\n不能够打开文件%s!\n",filename);}printf("\n打开文件%s成功!\n",filename);while (!feof(fp)) //判断是否已到文件末尾{fscanf (fp,"%c %d",&ch,&weight); //读取文件中的字符及权值fgetc(fp);fgetc(fp);//跳过回车HufNode[i].letter=ch; //将读取的字符存入Huffman数组中HufNode[i].weight=weight; //将读取的权值存入Huffman数组中++i;}fclose(fp); //关闭文件return i;}int CharWeight() //有文件随机生成字符权值{FILE *fp;ElemType ch;char filename[10];int weight,i=0,x;printf("\n请输入所要编码的文件名(如file1.txt):\n");scanf("%s",filename); //可以打开同目录下任意格式的文件fflush(stdin);if ((fp=fopen(filename,"rb"))==NULL) //若打开文件失败,直接返回{printf("\n不能够打开文件%s!\n",filename);}printf("\n打开文件%s成功!\n",filename);while (!feof(fp)) //判断是否已到文件末尾{ch=fgetc(fp); //从文件读取一个字符x=ch; //将读取字符的ASCII码作为数组下标Weight[x]++; //字符数加}fclose(fp); //关闭文件for (x=0;x<256;x++)if (Weight[x]!=0) //字符数非零{HufNode[i].letter=x; //将读取的字符存入Huffman数组中HufNode[i].weight=Weight[x]; //将读取的字符数作为权值存入Huffman数组中++i;}return i; //返回字符数}void select(int n,int *s1, int *s2){int min;for(int i=0;i<n;i++){if(HufNode[i].parent==-1){min=i;break;}}for(int i=0;i<=n;i++){if(HufNode[i].parent==-1&&HufNode[i].weight<HufNode[min].weight)min=i;}*s1=min;for(int i=0;i<=n;i++){if(HufNode[i].parent==-1&&i!=min){min=i;break;}}for(int i=1;i<=n;i++){if(HufNode[i].parent==-1&&i!=(*s1)&&HufNode[i].weight<HufNode[min].weight) min=i;}*s2=min;}int Huffman_Tree() //建立Huffman 树{int i,j,s1,s2,x1,x2;ElemType temp2;char temp3;for (i=0;i<2*HuffmanLeaf-1;++i) //节点初指针域初始化HufNode[i].parent=HufNode[i].lchild=HufNode[i].rchild=-1;for (i=HuffmanLeaf;i<2*HuffmanLeaf-1;++i) //节点存储信息{HufNode[i].letter=NULL;HufNode[i].weight=0;}/*非叶子结点初始化*//* ------------初始化完毕!---------*/for(i=HuffmanLeaf;i<2*HuffmanLeaf-1;i++) //创建非叶子结点,建哈夫曼树{ //在(*ht)[1]~(*ht)[i-1]的范围内选择两个parent为0且weight最小的结点,其序号分别赋值给s1、s2返回select(i-1 ,&s1,&s2);HufNode[s1].parent=i;HufNode[s2].parent=i;HufNode[i].lchild=s1; //规定左侧比右侧小HufNode[i].rchild=s2;HufNode[i].weight=HufNode[s1].weight+HufNode[s2].weight;}cout<<"\n成功创建Huffman树!是否保存?(Y/N)\n\t";temp3=getchar();fflush(stdin);while (temp3!='y'&&temp3!='Y'&&temp3=='n'&&temp3=='N'){cout<<"\n输入错误!!请确认是否保存?(Y/N)\n\t";temp3=getchar();fflush(stdin);}if (temp3=='y'||temp3=='Y')x1=SaveHuffmanTree(); //保存已生成的哈夫曼树while (!x1){cout<<"\n是否重新保存?(Y/N)\n\t";temp3=getchar();fflush(stdin);while (temp3!='y'&&temp3!='Y'&&temp3=='n'&&temp3=='N'){cout<<"\n输入错误!!请确认是否保存?(Y/N)\n\t";temp3=getchar();fflush(stdin);}if (temp3=='y'||temp3=='Y')x1=SaveHuffmanTree(); //保存已生成的哈夫曼树}void InitHuffman() //HuffMan树的初始化{//HufNode=new HuffmanTree[2*MAXLEAF-1];ElemType s[MAXLEAF]={0},ch;int i;cout<<" 请选择字符及相应权值的输入方式\n";cout<<"\t***********************\n";cout<<"\t 1—从文件读入\n";cout<<"\t 2—从键盘输入\n";cout<<"\t 3—由电文随机生成\n";cout<<"\t***********************\n";cout<<"\n请选择—:";ch=getchar(); //菜单选择fflush(stdin);while (ch>'3'||ch<'1'){cout<<"\n输入有误,请重新输入:";ch=getchar();fflush(stdin);}if (ch=='3')HuffmanLeaf=CharWeight(); //字符权值由电文随机生成else if (ch=='2'){ //字符及及相应权值由键盘输入cout<<"\n请输入一些字符(用#号结束):\n";char c;cin>>c;while(c!='#'){HufNode[HuffmanLeaf].letter=c;HuffmanLeaf++;cin>>c;}cout<<"\n请输入字符相应的权值:\n";for (i=0;i<HuffmanLeaf;i++) //输入字符相应的权值cin>>HufNode[i].weight;}elseHuffmanLeaf=WriteHuffman(); //调用已有文件中的字符及权值if (HuffmanLeaf){ //如果哈夫曼树的叶子数不为零Huffman_Tree(); //生成哈夫曼树Huffman_Code(HuffmanLeaf); //生成哈弗曼编码 //cout<<"此处应该去huffmantree.h";}}void LoadHuffmanTree() //调入已有的哈弗曼树进入内存{FILE *fp;int i=0;if ((fp=fopen("hfmantree.dat","rb"))==NULL){printf("\n文件hfmantree.dat不存在!\n");}for(i=0;i<MAXLEAF;i++) //得到结点总数if(fread(&HufNode[i],sizeof(HTNode),1,fp)!=1) break;//调入哈弗曼数fclose(fp);HuffmanLeaf=(i+1)/2; //叶子数printf("\n成功调入哈夫曼树!\n");Huffman_Code(HuffmanLeaf); //生成哈弗曼编码}#endif(4)哈弗曼编码生成模块:huffmancode.hvoid Huffman_Code(int HuffmanLeaf) //生成Huffman 编码{HuffmanCode cd;int i,j,c,p;for (i=0;i<HuffmanLeaf;i++) //按节点位置进行编码{cd.start=HuffmanLeaf-1; //编码长度最长为叶子数-1c=i;p=HufNode[c].parent; //指向叶子结点的双亲while (p!=-1) //编码结束标志{ //从叶子到结点逆向求编码if (HufNode[p].lchild==c)cd.bit[cd.start]='0'; //左孩子编码为elsecd.bit[cd.start]='1'; //右孩子编码为cd.start--; //左移一位c=p;p=HufNode[c].parent; //上移}for (j=cd.start+1;j<HuffmanLeaf;j++) //存储编码HuffCode[i].bit[j]=cd.bit[j];HuffCode[i].start=cd.start;}for(i=0;i<HuffmanLeaf;i++) //字符复制,字符与编码对应HuffCode[i].letter=HufNode[i].letter;printf("\n编码创建成功!\n");}int Show_HuffCode() //打印哈夫曼编码{int i,x;char t;if (HuffmanLeaf==0) //空树直接返回{cout<<"\n哈夫曼树还没被创建!\n";return ERROR;}cout<<"\n哈弗曼编码为:\n";for (i=0;i<HuffmanLeaf;i++){cout<<HuffCode[i].letter<<"\t"; //打印字符cout<<HuffCode[i].bit+HuffCode[i].start+1<<endl; //打印编码}cout<<"是否保存成\"hfmancode.txt\"文件(y保存,任意键继续):"<<endl;t=getchar();if(t=='y'||t=='Y')x=SaveHuffmanCode(); //将生成的哈弗曼编码保存到文件}int SaveHuffmanCode() //将已生成的哈夫曼编码存到文件{FILE *p; //文件指针int i;if ((p=fopen("hfmancode.txt","w"))==NULL) //文件打开失败则直接返回{printf("\n保存失败!\n");return ERROR;}fprintf(p,"letter\tcode\n");for (i=0;i<HuffmanLeaf;i++)fprintf(p,"%c\t%s\n",HuffCode[i].letter,HuffCode[i].bit+HuffCode[i].start+1);//写入txt文件fclose(p);printf("\n成功保存Haffman编码到hfmancode.txt!\n"); //写入txt文件成功return OK;}#endif(5)编码模块:charcode.hint CharCodeFile(ElemType s[MAXCHARNUM])//将文件电文调入内存{FILE *fp;char ch[2],filename[10];int i;for (i=0;i<MAXCHARNUM;++i)s[i]=NULL;printf("\n请输入所要编码的文件名(必须与前者生成编码的文件保持一致,如file1.txt):\n");scanf("%s",filename);//输入所需编码的文件名fflush(stdin);if ((fp=fopen(filename,"r"))==NULL)//文件空直接返回{printf("\n文件%s打开失败!\n",filename);return ERROR;}printf("\n文件%s打开成功!\n",filename);ch[1]='\0';ch[0]=fgetc(fp);while (ch[0]!=EOF)//文件结束判断{strcat(s,ch);ch[0]=fgetc(fp);}//写入内存fclose(fp);printf("\n%s的内容为:\n%s\n",filename,s);return OK;}int CharCode()//对电文进行编码{FILE *fp;ElemType s[MAXCHARNUM],*p;int i,j,n,m;if (HuffmanLeaf==0)//空树直接返回{printf("\n哈夫曼树还没被创建!\n");return ERROR;}if ((fp=fopen("file2.txt","w"))==NULL)//打开文件失败返回{printf("\n文件创建失败!\n");return ERROR;}p=s;m=CharCodeFile(p);//将文件电文调入内存if (m)//文件不为空{n=strlen(s);//计算电文长度for (i=0;i<n;i++){for (j=0;j<HuffmanLeaf;j++)if (s[i]==HuffCode[j].letter) break;fprintf(fp,"%s",HuffCode[j].bit+HuffCode[j].start+1);//打印文件内容}fclose(fp);//关闭文件指针printf("\n成功编码,并保存在\"file2.txt\"文件中!\n");//文件file2中保存了编码文件return OK;}elsereturn ERROR;}(6)电文译码模块:trancode.hint LoadCode(ElemType s[MAXCODENUM]) //文件译码{FILE *fp;char ch[2]={0},filename[10];int i;for (i=0;i<MAXCODENUM;++i)s[i]=NULL;printf("\n请输入所要译码的文件名(如file3.txt):\n");scanf("%s",filename); //输入所需译码的文件名fflush(stdin);if ((fp=fopen(filename,"r"))==NULL) //文件打开失败直接返回{printf("\n打开文件%s失败!\n",filename);return ERROR;}printf("\n打开文件%s成功!\n",filename);while ((ch[0]=fgetc(fp))!=EOF)strcat(s,ch); //将所需译码的文件内容调入内存return OK;}int HEncode() //电文译码{int c,x;ElemType code[MAXCODENUM],* m;FILE *fp;if ((fp=fopen("file4.txt","w"))==NULL) //打开所需译码的文件{printf("\n文件创建失败!\n");return ERROR;}if (HuffmanLeaf==0) //空树返回{printf("\n哈夫曼树还没被创建!\n");return ERROR;}x=LoadCode(code); //将所需译码文件调入内存if (x) //调入文件成功{printf("\n译码结果为:\n");m=code;c=2*HuffmanLeaf-2; //c指向根结点while (*m!=NULL) //译码{if (*m=='0') //编码为零{c=HufNode[c].lchild; //指向左孩子if (HufNode[c].lchild==-1&&HufNode[c].rchild==-1){ //到叶子结点,找与哈弗曼编码匹配的字符printf("%c",HufNode[c].letter); //打印字符fprintf(fp,"%c",HufNode[c].letter); //字符写入文件c=2*HuffmanLeaf-2;}} //译码成功,下一组继续else if (*m=='1') //编码为一{c=HufNode[c].rchild; //指向右孩子if (HufNode[c].lchild==-1&&HufNode[c].rchild==-1){ //到叶子结点,找与哈弗曼编码匹配的字符printf("%c",HufNode[c].letter); //打印字符fprintf(fp,"%c",HufNode[c].letter); //字符写入文件c=2*HuffmanLeaf-2;}} //译码成功,下一组继续m++; //指针后移}printf("\n\n");fclose(fp); //译码结果写入文件成功,关闭文件指针printf("\n保存到file4.txt成功!\n");return OK;}elsereturn ERROR;}#endif(7)菜单显示模块:huffmanmenue,hint doChoice(){char ch;while(1){cout<<"请选择0—6:";cin>>ch;fflush(stdin);switch (ch){case '1':InitHuffman(); //创建哈弗曼树break;case '2':LoadHuffmanTree(); //从文件中载入哈弗曼树break;case '3':Show_HuffCode(); //打印哈弗曼编码break;case '4':CharCode(); //对电文进行编码break;case '5':HEncode(); //对电文进行译码break;case '6':cout<<"\n~~~~(>_<)~~~~ 该功能暂未实现,期待新版本!~~~~(>_<)~~~~ \n";break;case '0':cout<<"\n\t******谢谢使用,再见!******\n";exit(0);break;default:cout<<"\n输入有误!\n";}cout<<"\n\t是否继续使用本系统:Y/N:";cin>>ch;if(ch=='N'||ch=='n'){cout<<"\n\t******谢谢使用,再见!******\n";exit(0);break;}system("cls"); //对前一屏幕的显示清空HuffmanMenu(); //重新载入菜单 }return 1;}void HuffmanMenu(){char ch;cout<<"\n\t 哈夫曼编码—译码器\n";cout<<"====================================\n";cout<<"\t1—创建哈夫曼树\n";cout<<"\t2—从文件读入哈夫曼树\n";cout<<"\t3—查看编码规则\n";cout<<"\t4—对电文进行编码\n";cout<<"\t5—对电文进行译码\n";cout<<"\t6—打印哈夫曼树\n";cout<<"\t0—退出\n";cout<<"====================================\n";doChoice();} (8)程序中各函数间的调用关系,如下图所示:四.测试:1.程序使用说明(1)本程序的运行环境为Dev-C++。