完整word版数据结构课程设计:电文编码译码哈夫曼编码

合集下载

数据结构设计课程设计-哈夫曼编译码系统的设计与实现

数据结构设计课程设计-哈夫曼编译码系统的设计与实现

20180902一、需求分析1、问题描述利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。

但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(解码)。

对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。

试为这样的信息收发站设计一个哈夫曼编译码系统。

2、基本要求(1)初始化(Initialzation)。

从数据文件DataFile.txt中读入字符及每个字符的权值,建立哈夫曼树HuffTree;(2)编码(EnCoding)。

用已建好的哈夫曼树,对文件ToBeTran.txt 中的文本进行编码形成报文,将报文写在文件Code.txt中;(3)译码(Decoding)。

利用已建好的哈夫曼树,对文件CodeFile.txt 中的代码进行解码形成原文,结果存入文件Textfile.txt中;(4)输出(Output)。

输出DataFile.txt中出现的字符以及各字符出现的频度(或概率);输出ToBeTran.txt及其报文Code.txt;输出CodeFile.txt及其原文Textfile.txt;二、概要设计1.数据结构本程序需要用到以一个结构体HTNode,以及一个二维数组HuffmanCode。

2.程序模块本程序包含两个模块,一个是实现功能的函数的模块,另一个是主函数模块。

系统子程序及功能设计本系统共有七个子程序,分别是:a.int min1(HuffmanTree t,int i)//进行比较b.void select(HuffmanTree t,int i,int *s1,int *s2)//求权值最小的两个数c.void HuffmanCoding(HuffmanTree *HT,HuffmanCode *HC,int *w,char *u,int n)///* w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n 个字符的赫夫曼编码HC */d.void Initialzation(HuffmanTree *HT,HuffmanCode *HC)//初始化e.int EnCoding(HuffmanTree *HT,HuffmanCode *HC)//对文件ToBeTran.txt中的文本进行编码形成报文,将报文写在文件Code.txt 中f.int pipei(char *c,int n,HuffmanCode *HC)//在huffmancode寻找匹配的编码g.void Decoding(HuffmanTree *HT,HuffmanCode *HC)//对文件CodeFile.txt中的代码进行解码形成原文,结果存入文件Textfile.txt中3.各模块之间的调用关系以及算法设计主函数调用Initialzation,EnCoding,Decoding。

数据结构课程设计:电文编码译码(哈夫曼编码)

数据结构课程设计:电文编码译码(哈夫曼编码)

xx农林大学计算机与信息学院数据结构课程设计设计:xx编译码器姓名:xx专业:2013级计算机科学与技术学号:班级:完成日期:2013.12.28xx编译码器一、需求分析在当今信息爆炸时代,如何采用有效的数据压缩技术节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视,哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。

哈夫曼编码是一种编码方式,以哈夫曼树—即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。

哈夫曼编码使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。

这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。

哈夫曼编码的应用很广泛,利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。

树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个叶子对应的字符的编码,这就是哈夫曼编码。

哈夫曼译码输入字符串可以把它编译成二进制代码,输入二进制代码时可以编译成字符串。

二、设计要求对输入的一串电文字符实现哈夫曼编码,再对哈夫曼编码生成的代码串进行译码,输出电文字符串。

通常我们把数据压缩的过程称为编码,解压缩的过程称为解码。

电报通信是传递文字的二进制码形式的字符串。

但在信息传递时,总希望总长度能尽可能短,即采用最短码。

假设每种字符在电文中出现的次数为Wi,编码长度为Li,电文中有n种字符,则电文编码总长度为∑WiLi。

若将此对应到二叉树上,Wi为叶结点的权,Li为根结点到叶结点的路径长度。

那么,∑WiLi恰好为二叉树上带权路径长度。

因此,设计电文总长最短的二进制前缀编码,就是以n种字符出现的频率作权,构造一棵哈夫曼树,此构造过程称为哈夫曼编码。

电文的编码和译码

电文的编码和译码

数据结构课程设计报告课程设计题目:电文的编码和译码姓名:***专业:信息管理与信息系统学号:************班级:*****指导教师:*****2014年6月东华理工大学课程设计评分表学生姓名:*** 班级:**** 学号:**********课程设计题目:电文的编码与译码一、需求分析 0二.设计内容 01)问题描述 02)设计要求 03)分析与实现 (1)4)功能要求 (1)5)概要设计 (2)三. 调试 (6)1)建立哈夫曼树 (6)2)编码 (7)3)译码 (8)四. 实验心得体会 (9)一、需求分析当今社会的一些领域,电文仍然被应用着,编写一个电文编码和译码系统还是有必要的,哈夫曼编码是广泛用于数据文件压缩的十分有效的编码方法。

其压缩通常在20%~90%之间。

哈夫曼编码算法使用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。

哈夫曼编码的应用很广泛,利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。

树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条分支上路径上的“0”或“1”的序列作为各个叶子对应的字符的编码,这就是哈夫曼编码。

该设计是对输入的一串电文字符实现哈夫曼编码,或对哈夫曼编码生成的代码串进行译码,输出电文字符串。

二.设计内容1)问题描述从键盘接收一串电文字符,输出对应的哈夫曼编码。

同时能翻译有哈夫曼编码生成的代码串,输出对应的电文字符串。

2)设计要求(1)构造一颗Huffman树。

(2)实现Huffman编码,并用Huffman编码生成的代码串进行译码。

(3)程序中字符和权值时可变的,实现程序的灵活性。

3)分析与实现在电报通信中,电文是以二进制代码传送的。

在发送时,需要将电文中的字符转换成二进制代码串,即编码;在接收时,要将收到的二进制代码转化为对应的字符序列,即译码。

我们知道,字符集中的字符被使用的频率是非均匀的。

数据结构课程设计 哈夫曼编码与译码器课程设计

数据结构课程设计 哈夫曼编码与译码器课程设计

数据结构课程设计题目名称:哈夫曼编码与译码器课程设计计算机科学与技术学院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)。

数据结构课程设计总结报告 哈夫曼编码译码

数据结构课程设计总结报告 哈夫曼编码译码

《数据结构》课程设计实验报告题目哈夫曼编码/译码器学院数理与信息学院专业计算机科学与技术班级计科132学生姓名刘海澍 5周弘杰8徐铭瑶 3指导教师编写日期数据结构课程设计目录1 问题描述.................................................................错误!未定义书签。

2 问题分析.................................................................错误!未定义书签。

3 算法设计 (2)3.1抽象数据类型定义 (2)3.2模块划分 (3)4 详细设计 (4)4.1数据类型的定义 (4)4.2主要模块的算法描述 (4)4.3 流程图 (6)5 测试分析 (9)6 课程设计总结 (10)7 成员分工 (10)参考文献 (11)附录(源程序清单) (12)1.问题描述设计一个利用哈夫曼算法的编码和译码系统,重复地显示并处理以下项目,直到选择退出为止。

1) 初始化:键盘输入字符集大小n、n个字符和n个权值,建立哈夫曼树;2) 编码:利用建好的哈夫曼树生成哈夫曼编码;3) 输出编码;4)显示哈夫曼树;5)界面设计的优化;6) 设字符集及频度如下表:字符空格 A B C D E F频度4 9 23 2 17 15字符G H I J K频度1 2 3 3 42.问题分析(1)定义一个变量名为HTNode的结构体,用该结构体中的char data、int weight、int parent、int lchild、int rchild分别表示哈夫曼树中每个结点的权值、权重、双亲结点、左孩子、右孩子,再定义一个HTNode类型的数组ht[60]存放哈夫曼树;另外定义一个变量名为HCode的结构体,采用HCode类型变量的cd[start]~cd[n]存放当前结点的哈夫曼编码、最后定义一个HCode类型的数组hcd[30]的数组用于存放当前叶子结点ht[i]的哈夫曼编码。

数据结构课程设计哈夫曼编码实验

数据结构课程设计哈夫曼编码实验

数据结构设计性实验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)练习通过普通树来构造霍夫曼树。

数据结构课程设计哈夫曼编码译码器.doc

数据结构课程设计哈夫曼编码译码器.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 超过次数限制。

完整word版哈夫曼编码译码器数据结构C语言模板

完整word版哈夫曼编码译码器数据结构C语言模板

一、需求分析目前,进行快速远距离通信的主要手段是电报,即将需传送的文字转化成由二级制的字符组成种字符,只需两个字符的串,便可”,它只有4的字符串。

例如,假设需传送的电文为“ABACCDA,00010010101100”则上述和11,7个字符的电文便为“以分辨。

假设A、B、C、D、的编码分别为00,01,10 14位,对方接受时,可按二位一分进行译码。

总长当然,在传送电文时,希望总长尽可能地短。

如果对每个字符设计长度不等的编码,且让电文DC、中出现次数较多的字符采用尽可能短的编码,则传送电文的总长便可减少。

如果设计A、B、。

但是,000011010”,则上述7个字符的电文可转换成总长为9的字符串“的编码分别为0,00,1,01”就可以有很多种译法,0000个字符的字串“这样的电文无法翻译,例如传送过去的字符串中前4”等。

因此,若要设计长短不等的编码,则必须是任一字ABAAAAA”或者“BB”,或者“或是“符的编码都不是另一个字符的编码的前缀,这种编码称作前缀编码。

然而,如何进行前缀编码就是利用哈夫曼树来做,也就有了现在的哈夫曼编码和译码。

二、概要设计译码利用哈夫曼树编/ 、建立哈夫曼树(一)、对哈夫曼树进行编码(二)、输出对应字符的编码(三)、译码过程(四)主要代码实现://结构体的定义struct code{char a;int w;int parent;int lchild;int rchild;};void creation(code *p,int n,int m); //建立哈夫曼树//编码void coding(code *p,int n);//输出函数void display(code *p,int n,int m);//译码void translate(char **hc,code *p,int n);详细设计三、(一)、建立哈夫曼树10序号:5 3 4 2 7 6 1* * *c *字符:db a 4 6 6 权值:10 6 4 2 3 3 1 d **33333 c*c * * 1 2 2 1 2 1 abb a 3-3图3-1 图b a 3-2 图1(二)、对哈夫曼树进行编码主要代码实现:从叶子到根逆向求编码for(c=i,f=p[i].parent;f!=0;c=f,f=p[f].parent){*'0'//左孩子编码为if(p[f].lchild==c) 1 { d* cd[--start]='0'; 0 1} c* 1 0 '1'else //右孩子编码为{ bacd[--start]='1';3-4图}}(三)、输出对应字符的码编码字符110 a111 b10 c3-1表d(四)、译码过程主要代码实现:0 比较两个字符串是否相等,相等则输出if(strcmp(a,hc[i])==0) //{或'1'确定找左孩子或右孩子//从根出发,按字符'0' for(c=2*n-1,j=0;a[j]!='\0';j++){if(a[j]=='0') //左孩子从跟到叶子顺向求字符{*c=p[c].lchild;1 0}d * else 1 0{c *右孩子c=p[c].rchild; // 1 0}ba }3-5 图2调试分析四、、数字的输入判断(一)4-1 图、字母的输入判断(二)4-2 图(三)、程序是否继续进行的判断4-3 图用户手册五、;提示输(一)、首先根据提示输入初始化数据,提示输入一个数字,请输入一个数a,0<a<9999中的一个字符;请勿在输入一个数字后再输入一个入一个字母,则请输入一个字母(a~z)或者(A~Z) 字符,或者在输入一个字符后再输入一个数字。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

福建农林大学计算机与信息学院数据结构课程设计设计:哈夫曼编译码器姓名:韦邦权专业:2013级计算机科学与技术学号:13224624班级:13052316完成日期:2013.12.281哈夫曼编译码器一、需求分析在当今信息爆炸时代,如何采用有效的数据压缩技术节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视,哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。

哈夫曼编码是一种编码方式,以哈夫曼树—即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。

哈夫曼编码使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。

这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。

哈夫曼编码的应用很广泛,利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。

树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个叶子对应的字符的编码,这就是哈夫曼编码。

哈夫曼译码输入字符串可以把它编译成二进制代码,输入二进制代码时可以编译成字符串。

二、设计要求对输入的一串电文字符实现哈夫曼编码,再对哈夫曼编码生成的2代码串进行译码,输出电文字符串。

通常我们把数据压缩的过程称为编码,解压缩的过程称为解码。

电报通信是传递文字的二进制码形式的字符串。

但在信息传递时,总希望总长度能尽可能短,即采用最短码。

假设每种字符在电文中出现的次数为Wi,编码长度为Li,电文中有n种字符,则电文编码总长度为∑WiLi。

若将此对应到二叉树上,Wi为叶结点的权,Li为根结点到叶结点的路径长度。

那么,∑WiLi 恰好为二叉树上带权路径长度。

因此,设计电文总长最短的二进制前缀编码,就是以n种字符出现的频率作权,构造一棵哈夫曼树,此构造过程称为哈夫曼编码。

设计实现的功能: (1) 哈夫曼树的建立;(2) 哈夫曼编码的生成; (3) 编码文件的译码。

三、概要设计哈夫曼编\译码器的主要功能是先建立哈夫曼树,然后利用建好的哈夫曼树生成哈夫曼编码后进行译码。

在数据通信中,经常需要将传送的文字转换成由二进制字符0、1组成的二进制串,称之为编码。

构造一棵哈夫曼树,规定哈夫曼树中的左分之代表0,右分支代表1,则从根节点到每个叶子节点所经过的路径分支组成的0和1的序列便为该节点对应字符的编码,称之为哈夫曼编码。

最简单的二进制编码方式是等长编码。

若采用不等长编码,让出现频率高的字符具有较短的编码,让出现频率低的字符具有较长的编码,这样可能缩短传送电文的总长度。

哈夫曼树课用于构造使电文的编码总长最短的编码方案。

3设计包含的几个方面:①哈夫曼树的建立赫夫曼树的建立由赫夫曼算法的定义可知,初始森林中共有n棵只含有根结点的二叉树。

算法的第二步是:将当前森林中的两棵根结点权值最小的二叉树,合并成一棵新的二叉树;每合并一次,森林中就减少一棵树,产生一个新结点。

显然要进行n-1次合并,所以共产生n-1个新结点,它们都是具有两个孩子的分支结点。

由此可知,最终求得的哈夫曼树中一共有2n-1个结点,其中n个结点是初始森林的n个孤立结点。

并且哈夫曼树中没有度数为1的分支结点。

我们可以利用一个大小为2n--1的一维数组来存储赫夫曼树中的结点。

定义的结构体类型如下:typedef struct{char data; //结点字符int weight; //权值int parent; //双亲结点int lchild; //左孩子结点int rchild; //右孩子结点}HTNode;②哈夫曼编码要求电文的哈夫曼编码,必须先定义哈夫曼编码类型,根据设计要求和实际需要定义的类型如下:typedet struct {char cd[N]; // 存放编码的数组int start; //从start 开始读cd中的哈夫曼编码}Hcode; // 编码结构体类型③代码文件的译码译码的基本思想是:读文件中编码,并与原先生成的哈夫曼编码表比较,遇到相等时,即取出其对应的字符存入一个新串中。

四、详细设计4①字符统计int jsq(char *s,int cnt[],char str[]){char *p;int i,j,k;for(i=1;i<=256;i++)cnt[i]=0;for(p=s;*p!='\0';p++){k=*p;cnt[k]++;}j=0;for(i=1,j=0;i<=256;i++)if(cnt[i]!=0){j++;}return j;}②哈夫曼树的算法void CreateHT(HTNode ht[],int n,char str[],int cn[]) //创建哈夫曼树函数{for(int input=1;input<=256;input++){str[input]=input;}int l=0;for(int output=1;output<=256;output++){if(cn[output] !=0){ht[l].data=str[output]; //按字母顺序将出现的字母依次存入数组ht[]ht[l].weight=cn[output];l++;}}int i,k,lnode,rnode;int min1,min2;for (i=0;i<2*n-1;i++)ht[i].parent=ht[i].lchild=ht[i].rchild=0; //所有结点的相关域置初值0 for (i=n;i<2*n-1;i++) //构造哈夫曼树{5min1=min2=MAX; //int的范围是-32768-32767lnode=rnode=0; //lnode和rnode记录最小权值的两个结点位置for (k=0;k<=i-1;k++) //选出每次外层循环最小权值的两个结点{if (ht[k].parent==0) //只在尚未构造二叉树的结点中查找{if (ht[k].weight<min1) //比min1小时{min2=min1;rnode=lnode;min1=ht[k].weight;lnode=k;}else if (ht[k].weight<min2) //比min1大,比min2小{min2=ht[k].weight;rnode=k;}}}ht[lnode].parent=i;ht[rnode].parent=i; //两个最小节点的父节点是iht[i].weight=ht[lnode].weight+ht[rnode].weight; //两个最小节点的父节点权值为两个最小节点权值之和ht[i].lchild=lnode;ht[i].rchild=rnode; //父节点的左节点和右节点}}③哈夫曼编码void CreateHCode(HTNode ht[],HCode hcd[],int n){int i,p,c;HCode hc;for (i=0;i<n;i++) //根据哈夫曼树求哈夫曼编码{hc.start=n; //初始位置c=i; //从叶子结点ht[i]开始上溯p=ht[i].parent;while (p!=0) //循序直到树根结点结束循环{hc.cd[hc.start--]=(ht[p].lchild)==c?'0':'1'; //左孩子记为0,右孩子记为1 c=p;p=ht[p].parent; //与上句c=i;p=ht[i].parent同义,促进循环}hc.start++; //start指向哈夫曼编码hc.cd[]中最开始字符hcd[i]=hc;}}6④哈夫曼译码void deHCode(HTNode ht[],HCode hcd[],int n,char str[]) //译码函数{牰湩晴尨输出译码结果为:\n);int i,j,k,x,m=0;char code[MAX];for (i=0;i<MAX;i++)for (j=0;j<n;j++)if(str[i]==ht[j].data) //循环查找与输入字符相同的编号,相同的就输出这个字符的编码{for (k=hcd[j].start;k<=n;k++){code[m]=hcd[j].cd[k]; //将输出的编码赋值到数组中m++;}break; //输出完成后跳出当前for循环}code[m]='#';//把要进行译码的字符串存入code数组中while(code[0]!='#')for (i=0;i<n;i++){m=0; //m为想同编码个数的计数器for (k=hcd[i].start,j=0;k<=n;k++,j++) //j为记录所存储这个字符的编码个数{if(code[j]==hcd[i].cd[k]) //当有相同编码时m值加1m++;}if(m==j) //当输入的字符串与所存储的编码字符串个数相等时则输出这个的data数据{printf(%c,ht[i].data);for(x=0;code[x-j]!='#';x++) //把已经使用过的code数组里的字符串删除{code[x]=code[x+j]; //删除j个数,往前移动j位}}}7printf(\);}⑤主函数void main(){char st[MAX],sst[MAX];int cn[257];int n,i;):\n); 任意字符请输入字符串(牰湩晴尨gets(st);n=jsq(st,cn,sst);///////////////////////////99for(i=0;i<99;i++)sst[i]=st[i];//////////////////////////////////HTNode ht[M];HCode hcd[N];CreateHT(ht,n,st,cn);CreateHCode(ht,hcd,n);outputHCode(ht,hcd,n);editHCode(ht,hcd,n,sst);deHCode(ht,hcd,n,sst);}五、调试输出哈夫曼编码8输出编码结果输出译码结果9附录源程序#include <stdio.h>//gets()函数需要#include <string.h>50叶节点数义用N表示// #define N 2562n-1 时总节点数为当叶节点数位n //用M表示节点总数#define M 2*N-1 #define MAX 32767typedef struct{结点字符// char data;//权值int weight;双亲结点// int parent;左孩子结点// int lchild;右孩子结点// int rchild;}HTNode;///////////////////////////typedef struct{存放哈夫曼码char cd[N]; // 10int start; //从start开始读cd中的哈夫曼码}HCode;///////////////////////////////////int jsq(char *s,int cnt[],char str[]){char *p;int i,j,k;for(i=1;i<=256;i++)cnt[i]=0;for(p=s;*p!='\0';p++){k=*p;cnt[k]++;}j=0;for(i=1,j=0;i<=256;i++)if(cnt[i]!=0){j++;}return j;}///////////////////////////////////////////////////void CreateHT(HTNode ht[],int n,char str[],int cn[]) //创建哈夫曼树函数{for(int input=1;input<=256;input++){str[input]=input;}int l=0;for(int output=1;output<=256;output++){if(cn[output] !=0){ht[l].data=str[output]; //按字母顺序将出现的字母依次存入数组ht[]ht[l].weight=cn[output];l++;}}int i,k,lnode,rnode;int min1,min2;for (i=0;i<2*n-1;i++)ht[i].parent=ht[i].lchild=ht[i].rchild=0; //所有结点的相关域置初值011for (i=n;i<2*n-1;i++) //构造哈夫曼树{min1=min2=MAX; //int的范围是-32768-32767lnode=rnode=0; //lnode和rnode记录最小权值的两个结点位置for (k=0;k<=i-1;k++) //选出每次外层循环最小权值的两个结点{if (ht[k].parent==0) //只在尚未构造二叉树的结点中查找{if (ht[k].weight<min1) //比min1小时{min2=min1;rnode=lnode;min1=ht[k].weight;lnode=k;}else if (ht[k].weight<min2) //比min1大,比min2小{min2=ht[k].weight;rnode=k;}}}ht[lnode].parent=i;ht[rnode].parent=i; //两个最小节点的父节点是iht[i].weight=ht[lnode].weight+ht[rnode].weight; //两个最小节点的父节点权值为两个最小节点权值之和ht[i].lchild=lnode;ht[i].rchild=rnode; //父节点的左节点和右节点}}//////////////////////////////////////////////////////void CreateHCode(HTNode ht[],HCode hcd[],int n){int i,p,c;HCode hc;for (i=0;i<n;i++) //根据哈夫曼树求哈夫曼编码{hc.start=n; //初始位置c=i; //从叶子结点ht[i]开始上溯p=ht[i].parent;while (p!=0) //循序直到树根结点结束循环{hc.cd[hc.start--]=(ht[p].lchild)==c?'0':'1'; //左孩子记为0,右孩子记为1 c=p;p=ht[p].parent; //与上句c=i;p=ht[i].parent同义,促进循环}hc.start++; //start指向哈夫曼编码hc.cd[]中最开始字符hcd[i]=hc;12}}/////////////////////////////////////////////////void outputHCode(HTNode ht[],HCode hcd[],int n) //输出哈夫曼编码的列表{int i,k;printf( 输出哈夫曼编码:\n);for (i=0;i<n;i++) //输出data中的所有数据,{printf( %c:\t,ht[i].data);for (k=hcd[i].start;k<=n;k++) //输出所有data中数据的编码{printf(%c,hcd[i].cd[k]); //从初最开始的字符起输出}printf(\);}}////////////////////////////////////////////void editHCode(HTNode ht[],HCode hcd[],int n,char str[]) //编码函数{int i,j,k;printf(\输出编码结果:\n);for (i=0;i<MAX;i++)for (j=0;j<n;j++)if(str[i]==ht[j].data) //循环查找与输入字符相同的编号,相同的就输出这个字符的编码{for (k=hcd[j].start;k<=n;k++){printf(%c,hcd[j].cd[k]);}break; //输出完成后跳出当前for循环}printf(\);}/////////////////////////////////////////////void deHCode(HTNode ht[],HCode hcd[],int n,char str[]) //译码函数牰湩晴尨输出译码结果为:\n);int i,j,k,x,m=0;char code[MAX];13for (i=0;i<MAX;i++)for (j=0;j<n;j++)if(str[i]==ht[j].data) //循环查找与输入字符相同的编号,相同的就输出这个字符的编码{for (k=hcd[j].start;k<=n;k++){code[m]=hcd[j].cd[k]; //将输出的编码赋值到数组中m++;}break; //输出完成后跳出当前for循环}code[m]='#';//把要进行译码的字符串存入code数组中while(code[0]!='#')for (i=0;i<n;i++){m=0; //m为想同编码个数的计数器for (k=hcd[i].start,j=0;k<=n;k++,j++) //j为记录所存储这个字符的编码个数{if(code[j]==hcd[i].cd[k]) //当有相同编码时m值加1m++;}if(m==j) //当输入的字符串与所存储的编码字符串个数相等时则输出这个的data数据{printf(%c,ht[i].data);for(x=0;code[x-j]!='#';x++) //把已经使用过的code数组里的字符串删除{code[x]=code[x+j]; //删除j个数,往前移动j位}}}printf(\}////////////////////////////////////////void main(){char st[MAX],sst[MAX];14int cn[257];int n,i;):\n); 任意字符请输入字符串(牰湩晴尨gets(st); n=jsq(st,cn,sst);///////////////////////////99for(i=0;i<99;i++)sst[i]=st[i];//////////////////////////////////HTNode ht[M];HCode hcd[N];CreateHT(ht,n,st,cn);CreateHCode(ht,hcd,n);outputHCode(ht,hcd,n);editHCode(ht,hcd,n,sst);deHCode(ht,hcd,n,sst);}15。

相关文档
最新文档