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

合集下载

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

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

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。

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

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

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

课程设计--哈夫曼编码与译码

课程设计--哈夫曼编码与译码

哈夫曼编码与译码学生姓名:指导老师:摘要本课程设计主要解决的是利用哈夫曼树生成的哈夫曼编码进行字符串的加密和解密,并将加密的编码写入文件。

在此课程设计中,系统开发平台为Windows XP,程序设计语言采用面向过程的高级语言C和面向对象的高级语言C++,程序运行平台为Visual C++ 6.0。

在程序设计中,采用了结构化与面向过程两种解决问题的方法。

程序通过调试运行,初步实现了设计目标,并且经过适当完善后,将可以应用在商业中解决实际问题。

关键词哈夫曼树,编码,译码,文件操作,C,C++;1 引言1.1 课题背景随着信息时代的到来,各种信息日益丰富,信息迅速膨胀,对信息管理的工作量也日益增大。

在信息化未到来之前,信息的存储编码也变得尤为重要,公司之间的信息需要编码,用户个人数据需要编码,都需要占用很大的空间,所以一个好的、高效的编码译码算法是十分重要的。

好的加密算法不仅可以降低管理方的工作量和存储量,还可以对用户的信息进行高效的管理,同时使在用中可以避免不必要的麻烦。

数据结构是指相互之间存在一定关系的数据元素的集合。

按照视点的不同,数据结构分为逻辑结构和存储结构。

数据的逻辑结构(logical structure)是指数据元素之间逻辑关系的整体。

所谓逻辑关系是指数据元素之间的关联方式或邻接关系。

根据数据元素之间逻辑关系的不同,数据结构分为四类:集合、线性结构、树结构、图结构。

数据的逻辑结构属于用户视图,是面向问题的,反映了数据内部的构成方式。

为了区别于数据的存储结构,常常将数据的逻辑结构称为数据结构。

数据的存储结构(storage structure)又称为物理结构,是数据及其逻辑结构在计算机中的表示,换言之,存储结构除了数据元素之外,必须隐式或显示地存储数据元素之间的逻辑关系。

通常有两种存储结构:顺序存储结构和链接存储结构。

树是一种在实际应用中被广泛使用的数据结构。

它是由同一类型的记录构成的集合。

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

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

哈夫曼编码译码器哈夫曼编码译码器a)需求分析:一个完整的系统应具有以下功能:(l)I:初始化。

从终端读入字符集大小n,及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmtree中。

(2)C:编码。

利用已建好的哈夫曼树(如不在内存,则从文件hfmtree 中读入),对文件tobetrans中的正文进行编码,然后将结果存入文件codefile中。

(3)D:编码。

利用已建好的哈夫曼树将文件codefile中的代码进行译码,结果存入文件textfile中。

(4)P:印代码文件。

将文件codefile以紧凑格式显示在终端上,每行50个代码。

同时将此字符形式的编码文件写入文件codeprint中。

(5)T:印哈夫曼树。

将已在内存中的哈夫曼树以直观的方式 (树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件treeprint 中可以根据题目要求把程序划成5个模块,设计成菜单方式,每次执行一个模块后返回菜单。

除了初始化(I)过程外,在每次执行时都经过一次读取磁盘文件数据。

这是为了如果在程序执行后一直没有进行初始化(I)过程,为了能使后面的操作顺利进行,可以通过读取旧的数据来进行工作。

比如:如果程序的工作需要的字符集和权值数据是固定的,只要在安装程序时进行一次初始(I)化操作就可以了。

在再次运行程序时,不管进行那项操作都可以把需要的数据读入到内存。

b)概要设计本程序主要用到了三个算法。

(1)哈夫曼编码在初始化(I)的过程中间,要用输入的字符和权值建立哈夫曼树并求得哈夫曼编码。

先将输入的字符和权值存放到一个结构体数组中,建立哈夫曼树,将计算所得的哈夫曼编码存储到另一个结构体数组中。

(2)串的匹配在编码(D)的过程中间,要对已经编码过的代码译码,可利用循环,将代码中的与哈夫曼编码的长度相同的串与这个哈夫曼编码比较,如果相等就回显并存入文件。

(3)二叉树的遍历在印哈夫曼树(T)的中,因为哈夫曼树也是二叉树,所以就要利用二叉树的先序遍历将哈夫曼树输出c)详细设计构造树的方法如下:初始化:每个字符就是一个结点,字符的频度就是结点的权;1、将结点按频度从小到大排序;2、选取频度最小的两个结点,以它们为儿子,构造出一个新的结点;新结点的权值就是它两个儿子的权值之和;构造之后,从原来的结点序列里删除刚才选出的那两个结点,但同时将新生成的结点加进去;3、如果结点序列里只剩下一个结点,表示构造完毕,退出。

电文的编码和译码简单Huffman编码译码的设计与实现

电文的编码和译码简单Huffman编码译码的设计与实现

电文的编码和译码简单Huffman编码译码的设计与实现三、题目--赫夫曼编码/译码器1. 问题描述利用赫夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。

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

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

试为这样的信息收发站编写一个赫夫曼码的编/译码系统。

2.基本要求一个完整的系统应具有以下功能:(1) I:初始化(Initialization)。

从终端读入字符集大小n,以及n个字符和n个权值,建立赫夫曼树,并将它存于文件hfmTree中。

(2) E:编码(Encoding)。

利用已建好的赫夫曼树(如不在内存,则从文件hfmTree中读入),对文件T oBeTran中的正文进行编码,然后将结果存入文件CodeFile中。

(3) D:译码(Decoding)。

利用已建好的赫夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。

以下为选做:(4) P:印代码文件(Print)。

将文件CodeFile以紧凑格式显示在终端上,每行50个代码。

同时将此字符形式的编码文件写入文件CodePrin中。

(5) T:印赫夫曼树(Tree printing)。

将已在内存中的赫夫曼树以直观的方式(比如树)显示在终端上,同时将此字符形式的赫夫曼树写入文件TreePrint 中。

3.测试要求(1) 已知某系统在通信联络中只可能出现八种字符,其频率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计赫夫曼编码。

(2) 用下表给出的字符集和频度的实际统计数据建立赫夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FAVORITE”。

字符 A B C D E F G H I J K L M频度186 64 13 22 32 103 21 15 47 57 1 5 32 20字符N O P Q R S T U V W X Y Z频度57 63 15 1 48 51 80 23 8 18 1 16 1四、概要设计1)问题分析哈夫曼树的定义1.哈夫曼树节点的数据类型定义为:typedef struct{ //赫夫曼树的结构体char ch;int weight; //权值int parent,lchild,rchild;}htnode,*hfmtree;2)所实现的功能函数如下1、void hfmcoding(hfmtree &HT,hfmcode &HC,int n)初始化哈夫曼树,处理InputHuffman(Huffman Hfm)函数得到的数据,按照哈夫曼规则建立2叉树。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

设计包含的几个方面:①xx树的建立赫夫曼树的建立由赫夫曼算法的定义可知,初始森林中共有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;②xx编码要求电文的哈夫曼编码,必须先定义哈夫曼编码类型,根据设计要求和实际需要定义的类型如下:typedet struct {char cd[N]; //存放编码的数组int start;//从start 开始读cd中的哈夫曼编码}Hcode; //编码结构体类型③代码文件的译码译码的基本思想是:读文件中编码,并与原先生成的哈夫曼编码表比较,遇到相等时,即取出其对应的字符存入一个新串中。

四、详细设计①字符统计{char *p;int i,j,k;for(i=1;i<=256;i++)for(p=s;*p!='\0';p++){k=*p;for(i=1,j=0;i<=256;i++){ht[l].data=str[output];//按字母顺序将出现的字母依次存入数组ht[]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;//所有结点的相关域置初值0for (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;//两个最小节点的父节点是i ht[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,右孩子记为1c=p;p=ht[p].parent;//与上句c=i;p=ht[i].parent同义,促进循环}hc.start++;//start指向哈夫曼编码hc.cd[]中最开始字符hcd[i]=hc;}}④xx译码void deHCode(HTNode ht[],HCode hcd[],int n,char str[])//译码函数{printf("输出译码结果为:\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位}}}printf("\n");}⑤主函数void main(){char st[MAX],sst[MAX];int n,i;printf("请输入字符串(任意字符): \n");gets(st);///////////////////////////99for(i=0;i<99;i++)sst[i]=st[i];////////////////////////////////// HTNode ht[M];HCode hcd[N];CreateHCode(ht,hcd,n); outputHCode(ht,hcd,n); editHCode(ht,hcd,n,sst); deHCode(ht,hcd,n,sst);}五、调试输出xx编码输出编码结果输出译码结果附录源程序#include <stdio.h>#include <string.h>//gets()函数需要#define N 256//义用N表示50叶节点数#define M 2*N-1//用M表示节点总数当叶节点数位n时总节点数为2n-1#define MAX 32767typedef struct {char data;//结点字符int weight;//权值int parent;//双亲结点int lchild;//左孩子结点int rchild;//右孩子结点}HTNode;///////////////////////////typedef struct {char cd[N];//存放哈夫曼码int start;//从start开始读cd中的哈夫曼码}HCode;///////////////////////////////////{char *p;int i,j,k;for(i=1;i<=256;i++)for(p=s;*p!='\0';p++){k=*p;for(i=1,j=0;i<=256;i++){ht[l].data=str[output];//按字母顺序将出现的字母依次存入数组ht[]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;//所有结点的相关域置初值0for (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;//两个最小节点的父节点是i ht[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,右孩子记为1c=p;p=ht[p].parent;//与上句c=i;p=ht[i].parent同义,促进循环}hc.start++;//start指向哈夫曼编码hc.cd[]中最开始字符hcd[i]=hc;}}/////////////////////////////////////////////////void outputHCode(HTNode ht[],HCode hcd[],int n)//输出哈夫曼编码的列表{int i,k;printf("输出xx编码:\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("\n");}}////////////////////////////////////////////void editHCode(HTNode ht[],HCode hcd[],int n,char str[])//编码函数{int i,j,k;printf("\n输出编码结果:\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("\n");}/////////////////////////////////////////////void deHCode(HTNode ht[],HCode hcd[],int n,char str[])//译码函数{printf("输出译码结果为:\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位}}}printf("\n");}////////////////////////////////////////void main(){char st[MAX],sst[MAX];int n,i;printf("请输入字符串(任意字符):\n");gets(st);///////////////////////////99for(i=0;i<99;i++)sst[i]=st[i];//////////////////////////////////HTNode ht[M];HCode hcd[N];CreateHCode(ht,hcd,n);outputHCode(ht,hcd,n);editHCode(ht,hcd,n,sst);deHCode(ht,hcd,n,sst);}。

相关文档
最新文档