哈夫曼编码课程设计
- 格式:doc
- 大小:170.00 KB
- 文档页数:9
哈夫曼编码译码器课程设计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章需求分析 (1)第2章总体设计 (1)第3章抽象数据类型定义 (2)3.1 哈夫曼编码与译码抽象数据类型的设计 (2)第4章详细设计 (2)4.1 工程视图 (2)4.2 类图视图 (3)4.3 函数的调用关系 (3)4.4 主程序流程图 (4)4.5 主要算法的流程图 (5)第5章测试 (7)第6章总结 (8)附录:程序代码 (9)第1章需求分析Huffman编码和译码根据给定的字符集和各字符的频率值,求出其中给定字符Huffman编码,并针对一段文本(定义在该字符集上)进行编码和译码,实现一个Huffman编码/译码系统。
要求设计类(或类模板)来描述Huffman树及其操作,包含必要的构造函数和析构函数,以及其他能够完成如下功能的成员函数:求Huffman编码输入字符串,求出编码输入一段编码,实现译码并设计主函数测试该类。
第2章总体设计图2.1主函数:对输入的字符段进行存储,并对字符数和对应的权值(字符个数)进行统计存储。
哈夫曼树初始化函数:对给定的字符数和权值,创建一棵哈夫曼树。
权值大小比较函数:找到每次所给集合的最小值和次小值,并返回给哈夫曼树初始化函数。
哈夫曼树编码函数:对创建的哈夫曼树,为左孩子的赋值为0,右孩子赋值为1,然后对叶子结点依次编码。
哈夫曼树译码函数:对输入的01二进制数一一与叶子结点的编码依次比较匹配。
第3章抽象数据类型定义3.1哈夫曼编码与译码抽象数据类型的设计enum Child{none,lchild,rchild}; //采用枚举,标记是左孩子还是右孩子class element //元素类{public://类的公有成员elememt(); //构造函数void change(char l,char *c,int p,Child h,int w) //对对象进行修改操作void getparent(int p) //对父结点的值进行修改操作void geta(Child h) //对孩子结点进行修改操作void getweight(int w) //对权值进行修改操作int returnweight() //返回权值操作friend void Select(element h[],int k,int *a,int *b);//友元函数的声明friend void HuffmanTreeCode(element HT[]);friend void HuffmanTreeYima(element huff[],char cod[],int b);private://类的私有成员char letter,*code; //letter为字符,*code指向编码字符串int weight; //权值int parent; //父结点Child a; //为父结点的左孩子还是右孩子};第4章详细设计4.1工程视图图4.1工程视图4.2 类图视图图4.2类图视图4.3 函数的调用关系 如下图:图4.3函数调用关系图主函数main()哈夫曼初始化函数 InitHuffmanTree () 寻找最小和次小结点函数 Select() 字符编码函数 HuffmanTreeCode () 字符译码函数 HuffmanTreeYima ()4.4主程序流程图4.5主要算法的流程图图4.5.1哈夫曼编码函数图4.5.2哈夫曼译码函数图5.1哈夫曼编码与译码这次课程设计写得比较仓促,程序许多处仍需要完善和修改。
(一) 哈夫曼树的设计思想对于一组具有确定权值的叶子结点可以构造出多个具有不同带权路径长度的二叉树,其中具有最小带权路径长度的二叉树称作哈夫曼树或者最优二叉树。
首先给定n 个权值创造n 个只含根结点的二叉树,得到一个二叉树林;再在这二叉树林里面找根结点的权值最小和次小的两棵树作成新的二叉树,其中新的二叉树的根结点的权值为摆布子根结点权值之和;最后在二叉树林中把组合过的二叉树删除,再重复第二步,直到最后就剩一颗二叉树的时候得到的这棵二叉树就是哈夫曼树。
(二)哈夫曼编码与解码的设计思想在数据通讯中,时常要将传送的文字转换为二进制字符0 和1 组成的二进制串,称这个过程为编码。
与子相对的是解码或者是译码,就是用与编码相同的方式将二进制串转换称编码前的文字的过程称作解码。
在这里是通过哈夫曼树实现编码与解码的,所以称作是哈夫曼编码与解码。
首先输入一个字符串,还有相应的在哈夫曼树里的权值,这样用哈夫曼树把字符串用二进制串代替它,这个过程要注意树和编码问题,其中树的问题在上面已经解决,主要看编码的问题,就是根据我们输入的字符串和权值建立相应的树模型,这一步完成那编码就已经完成为了,最后打印就行了;然后就是解码,完成编码相应的解码就相对简单了,就是先找到在编码的时候建的那个模型树,将编码中的二进制串再根据权值转换为相应的字符串,这样一步步解码就行了。
以上就是通过用哈夫曼树进行哈夫曼编码与解码如何实现的主要设计思想。
(一)哈夫曼树的流程图不 是图 1 哈夫曼树的流程图(二)编码与解码的流程图图 2 编码与解码的流程图图片说明: (左边)编码流程图, (右边)解码流程图。
开始输入字符串判断权值 建立路径有最小和次小 循环建立二叉树根据树对路径分左 0右 1写出对应结点的编码结束开始初始化哈夫曼链表二叉树林找最小和次小 的二叉树组合成新的二叉树 删除用过的二叉树是不是最后一 个二叉树是结束开始找到树的根结点 输入二进制串扫描根据树的路径打印对应字符继续扫描 是否结束是输出字符串结束否下面给出的是用中缀转后缀算法实现的程序的源代码:#include "stdio.h"#include "string.h"#define MAX 100struct HaffNode{int weight;int parent;char ch;int lchild;int rchild;}*myHaffTree;struct Coding{char bit[MAX];char ch;int weight;}*myHaffCode;void Haffman(int n){int i,j,x1,x2,s1,s2;for (i=n+1;i<=2*n-1;i++) {s1=s2=10000;x1=x2=0;for (j=1;j<=i-1;j++)/*定义常量*//*权值*//*双亲结点下标*//*构造哈夫曼树*//*定义数组*//*字符的权值*//*定义结构体*//*定义哈夫曼函数*//*树的初始化*//*构造哈夫曼树的非叶子结点*/{if(myHaffTree[j].parent==0&&myHaffTree[j].weight<s1){s2=s1;x2=x1;s1=myHaffTree[j].weight;x1=j;/*分配摆布结点*/}else if(myHaffTree[j].parent==0&&myHaffTree[j].weight<s2){s2=myHaffTree[j].weight;x2=j;}}myHaffTree[x1].parent=i;myHaffTree[x2].parent=i;myHaffTree[i].weight=s1+s2;myHaffTree[i].lchild=x1;myHaffTree[i].rchild=x2;/*摆布子组合为新树*/}}void HaffmanCode(int n){int start,c,f,i,j,k;char *cd;/*构造n 个结点哈夫曼编码*/cd=(char *)malloc(n*sizeof(char));myHaffCode=(struct Coding *)malloc((n+1)*sizeof(struct Coding));cd[n-1]='\0';for(i=1;i<=n;++i) /*n 个叶子结点的哈夫曼编码*/ {start=n-1;for(c=i,f=myHaffTree[i].parent;f!=0;c=f,f=myHaffTree[f].parent)if(myHaffTree[f].lchild==c) cd[--start]='0';else cd[--start]='1';for(j=start,k=0;j<n;j++){myHaffCode[i].bit[k]=cd[j];k++;}myHaffCode[i].ch=myHaffTree[i].ch; myHaffCode[i].weight=myHaffTree[i].weight; }free(cd);}Init(){int i,n,m;printf("please input the number of words:"); scanf("%d",&n); /*取编码对应的权值*//*定义有返回值的函数*/m=2*n-1;myHaffTree=(struct HaffNode *)malloc(sizeof(struct HaffNode)*(m+1)); for(i=1;i<=n;i++){printf("please input the word and the equal:");scanf("%s%d",&myHaffTree[i].ch,&myHaffTree[i].weight); myHaffTree[i].parent=0;myHaffTree[i].lchild=0;myHaffTree[i].rchild=0;}for(i=n+1;i<=m;i++){myHaffTree[i].ch ='#';myHaffTree[i].lchild=0;myHaffTree[i].parent=0;myHaffTree[i].rchild=0;myHaffTree[i].weight=0;}Haffman(n);HaffmanCode(n);for(i=1;i<=n;i++){printf("%c %d",myHaffCode[i].ch,myHaffCode[i].weight); printf("\n");}printf("init success!\n");return n;}void Caozuo_C(int m){int n,i,j;char string[50],*p;printf("please input the words :"); scanf("%s",string);n=strlen(string);for(i=1,p=string;i<=n;i++,p++){for(j=1;j<=m;j++)if(myHaffCode[j].ch==*p)printf("%s\n",myHaffCode[j].bit); }}void Caozuo_D(int n){int i,c;char code[1000],*p;printf("please input the coding:"); scanf("%s",code);for(p=code,c=2*n-1;*p!='\0';p++) {if(*p=='0'){c=myHaffTree[c].lchild;if(myHaffTree[c].lchild==0){printf("%c",myHaffTree[c].ch);c=2*n-1;continue;/* 编码函数*//*计算字符串长度*/ /*进行编码*//*解码函数*//*输入二进制编码*//*进行解码*//*结束条件*//*赋值*//* 扫描*//*结束*/}}else if(*p=='1'){c=myHaffTree[c].rchild;if(myHaffTree[c].lchild==0){printf("%c",myHaffTree[c].ch);c=2*n-1; /*赋值*/continue;}}}printf("\n");}void main(){int n;char char1;n=Init();printf("A.coding B.codeprintingwhile(1){scanf("%c",&char1);if(char1=='c')break;switch(char1){case'A':Caozuo_C(n);break;case'B':Caozuo_D(n);break;case'C':;break;}}}/*主函数*//*定义字符*//*函数的调用*/C.exit\nplease input the process:\n");/*判断字符*//*执行编码操作*//*执行解码操作*/哈夫曼编码与解码的实现(一)中缀转后缀算法的运行结果:这部份我主要遇到了如下三个问题,其内容与解决方法如下所列:问题1:刚开始不知道如何建一个好树,因为我开始试着建了几个二叉树,不知道什么原因运行的时候那编码总是不对,跟在草稿纸上自己画的那个二叉树总是不相符,就找原因。
目录1设计内容与设计要求 (1)1.1系统的基本功能 (2)1.2系统的设计要求 (2)2 系统需求分析 (1)2.1系统设计目标 (1)2.2哈夫曼算法 (1)3系统的实现 (3)4 程序调试 (3)5 总结 (3)5.1本系统特色 (3)5.2心得体会 (3)附件:源程序清单 (5)1设计内容与设计要求1.1系统的基本功能哈夫曼编码是根据字符出现频率对数据进行编码解码,以便对文件进行压缩的一种方法,目前大部分有效的压缩算法(如MP3编码方法)都是基于哈夫曼编码的。
数据压缩过程称为编码,也就是把文件中的每个字符均转换为一个唯一的二进制串。
数据解压过程称为解码,也就是把给定的二进制位字符串转换为对应的字符。
1.2系统的设计要求(1)数据结构可以使用结构体数组或结构体链表实现,结构体的属性可进行扩充。
(2)由用户输入相应文本。
(3)对于系统运行时,要求有相应的提示信息,方便用户进行选择。
2 系统需求分析2.1系统设计目标(1)哈夫曼树的建立。
(2)哈夫曼编码的生成。
(3)求出平均查找长度。
(4)用户输入权值的个数。
(5)输出的形式为整型。
(6)程序的执行可使用户在输入一列数值后,可得到由这些权值所得到的编码。
2.2 哈夫曼算法哈夫曼算法流程如下:(1)根据给定的N个权值{W1,W2,····,WN}构成N棵二叉树的集合F={T1,T2,T3,···,Tn},其中每棵二叉树Ti中只有一个带权为Wi的根节点,其左右子树均空。
(2)在F中选取两颗根节点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值最小的树为其左右子树上根节点的权值之和。
(3)在F中删除这两棵树,同时将新得到的二叉树加入F中。
(4)重复(2)和(3),直到F只含一棵树为止。
这棵树便是哈夫曼树。
(5)约定左分支表示字符‘0’,右分支表示字符‘1’,则可以从根结点到叶子结点的路径上分支字符组成的字符串作为该叶子结点字符的编码,这就是哈夫曼编码。
数据结构设计性实验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)编/译码器二、问题描述利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
哈夫曼编码与译码学生姓名:指导老师:摘要本课程设计主要解决的是利用哈夫曼树生成的哈夫曼编码进行字符串的加密和解密,并将加密的编码写入文件。
在此课程设计中,系统开发平台为Windows XP,程序设计语言采用面向过程的高级语言C和面向对象的高级语言C++,程序运行平台为Visual C++ 6.0。
在程序设计中,采用了结构化与面向过程两种解决问题的方法。
程序通过调试运行,初步实现了设计目标,并且经过适当完善后,将可以应用在商业中解决实际问题。
关键词哈夫曼树,编码,译码,文件操作,C,C++;1 引言1.1 课题背景随着信息时代的到来,各种信息日益丰富,信息迅速膨胀,对信息管理的工作量也日益增大。
在信息化未到来之前,信息的存储编码也变得尤为重要,公司之间的信息需要编码,用户个人数据需要编码,都需要占用很大的空间,所以一个好的、高效的编码译码算法是十分重要的。
好的加密算法不仅可以降低管理方的工作量和存储量,还可以对用户的信息进行高效的管理,同时使在用中可以避免不必要的麻烦。
数据结构是指相互之间存在一定关系的数据元素的集合。
按照视点的不同,数据结构分为逻辑结构和存储结构。
数据的逻辑结构(logical structure)是指数据元素之间逻辑关系的整体。
所谓逻辑关系是指数据元素之间的关联方式或邻接关系。
根据数据元素之间逻辑关系的不同,数据结构分为四类:集合、线性结构、树结构、图结构。
数据的逻辑结构属于用户视图,是面向问题的,反映了数据内部的构成方式。
为了区别于数据的存储结构,常常将数据的逻辑结构称为数据结构。
数据的存储结构(storage structure)又称为物理结构,是数据及其逻辑结构在计算机中的表示,换言之,存储结构除了数据元素之外,必须隐式或显示地存储数据元素之间的逻辑关系。
通常有两种存储结构:顺序存储结构和链接存储结构。
树是一种在实际应用中被广泛使用的数据结构。
它是由同一类型的记录构成的集合。
c 哈夫曼编码课程设计一、课程目标知识目标:1. 学生能理解哈夫曼编码的基本原理,掌握其构建过程和应用场景。
2. 学生能运用哈夫曼编码进行数据压缩,并了解压缩比的概念。
3. 学生能理解哈夫曼编码在通信、图像处理等领域的重要性。
技能目标:1. 学生能够运用所学知识,独立构建哈夫曼树并进行编码。
2. 学生能够分析给定数据,选择合适的编码方法进行数据压缩。
3. 学生能够运用编程工具实现哈夫曼编码和解码过程。
情感态度价值观目标:1. 学生通过学习哈夫曼编码,培养对数据压缩技术的兴趣,提高信息素养。
2. 学生在合作学习过程中,培养团队协作能力和沟通能力。
3. 学生了解我国在数据压缩领域的研究成果,增强民族自豪感。
课程性质:本课程为信息技术课程,旨在帮助学生掌握数据压缩的基本方法,提高数据处理能力。
学生特点:学生处于高年级阶段,具备一定的编程基础和逻辑思维能力。
教学要求:结合学生特点和课程性质,注重理论与实践相结合,培养学生的实际操作能力和创新能力。
通过分解课程目标为具体学习成果,使学生在学习过程中能够明确自身的学习进度和目标。
二、教学内容1. 哈夫曼编码基本原理:介绍哈夫曼编码的概念、原理和优势,结合教材相关章节,使学生理解哈夫曼编码在数据压缩中的应用。
- 哈夫曼树的构建方法- 哈夫曼编码的生成过程- 压缩比的概念及其计算方法2. 哈夫曼编码的实际操作:通过实际操作,让学生掌握哈夫曼编码的构建和编码过程。
- 利用编程工具实现哈夫曼树的构建- 编程实现哈夫曼编码的生成- 数据压缩与解压缩的实际操作3. 哈夫曼编码的应用案例分析:结合教材案例,分析哈夫曼编码在通信、图像处理等领域的作用。
- 通信领域的数据压缩- 图像处理中的哈夫曼编码应用- 其他领域中的应用案例4. 编程实践:布置相关编程任务,巩固学生对哈夫曼编码的理解和应用。
- 实现哈夫曼编码的压缩和解压缩程序- 分析不同数据集的压缩效果,优化哈夫曼编码方法教学内容安排和进度:第1课时:哈夫曼编码基本原理及构建方法第2课时:哈夫曼编码的实际操作(构建哈夫曼树、生成编码)第3课时:哈夫曼编码的应用案例分析第4课时:编程实践(实现压缩与解压缩程序,优化编码方法)三、教学方法本课程将采用以下教学方法,以促进学生的主动参与和深入理解:1. 讲授法:对于哈夫曼编码的基本原理和概念,通过教师清晰的讲解,结合教材内容,使学生快速掌握理论基础。
目录目录 (1)1 课程设计的目的和意义 (3)2 需求分析 (5)3 系统设计 (6)(1)设计思路及方案 (6)(2)模块的设计及介绍 (6)(3)主要模块程序流程图 (9)4 系统实现 (14)(1)主调函数 (14)(2)建立HuffmanTree (14)(3)生成Huffman编码并写入文件 (18)(4)电文译码 (19)5 系统调试 (22)小结 (25)参考文献 (26)附录源程序 (27)1 课程设计的目的和意义在当今信息爆炸时代,如何采用有效的数据压缩技术来节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视。
哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。
哈夫曼编码的应用很广泛,利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。
树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0"码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1"的序列作为和各个对应的字符的编码,这就是哈夫曼编码。
通常我们把数据压缩的过程称为编码,解压缩的过程称为解码。
电报通信是传递文字的二进制码形式的字符串。
但在信息传递时,总希望总长度尽可能最短,即采用最短码。
作为软件工程专业的学生,我们应该很好的掌握这门技术。
在课堂上,我们能过学到许多的理论知识,但我们很少有过自己动手实践的机会!课程设计就是为解决这个问题提供了一个平台。
在课程设计过程中,我们每个人选择一个课题,认真研究,根据课堂讲授内容,借助书本,自己动手实践。
这样不但有助于我们消化课堂所讲解的内容,还可以增强我们的独立思考能力和动手能力;通过编写实验代码和调试运行,我们可以逐步积累调试C程序的经验并逐渐培养我们的编程能力、用计算机解决实际问题的能力。
在课程设计过程中,我们不但有自己的独立思考,还借助各种参考文献来帮助我们完成系统。
更为重要的是,我们同学之间加强了交流,在对问题的认识方面可以交换不同的意见.同时,师生之间的互动也随之改善,我们可以通过具体的实例来从老师那学到更多的实用的知识。
湖南科技学院课程设计报告课程名称:数据结构课程设计课程设计题目:哈夫曼编码系:数学与计算科学系专业:信息与计算科学年级、班:信计0901姓名:郭如华学号:200905002145指导教师:牛志毅职称:讲师2011年12月目录1 问题描述 (3)2 基本要求 (3)3 测试数据 (3)4 算法思想 (3)5 模块划分 (3)6 数据结构 (3)7 源程序 (4)8 测试情况 (9)9 设计总结 (9)10参考资料 (9)1 问题描述设计一个哈夫曼编码系统,对文档中的报文进行编码,输出这段报文的哈夫曼编码,并且可以对输入的哈夫曼编码进行译码。
2 基本要求从文档中读取报文(如"what did you do that made you so happy")进行编码输出这段报文的哈夫曼编码。
3 测试数据what did you do that made you so happy4算法思想①:从文件中读取lei.txt并到数组z(保存所有字符的种类),读取data,txt存到数组ch(保存统计频数的一个样本)。
②:对数组z和数组ch进行比较统计出每个字符出现的频数,以频数代替权值,并把权值赋值到ht.weight的的数组中。
③:利用权值创建哈夫曼树。
④:利用哈夫曼树求的哈夫曼编码。
把lei.txt的数据赋值到hcd.ch中,把编好的哈夫曼编码赋值到hcd.code,则hcd这个数组就是一个哈夫曼编码的集合,hcd.ch 对应的下标就是这个字符所对应的哈夫曼编码。
⑤:输入要编码的字符,保存到ch数组,把ch数组的ch[j]元素逐个与hcd[i].ch 比较找出下标i,则hcd[i].code为ch[j]元素的哈夫曼编码。
⑥:输入要译码的哈夫曼编码lcd,逐个与hcd[i].code比较,找出下标i,则hcd[i].ch 为lcd所对应的字符。
5 模块划分①:void inithuffmantree(huffmantree ht);/*初始化哈夫曼树*/②:void tongji(huffmantree ht,huffmancode hcd,char *ch,char *z);/*统计权值*/③:void selectmin(huffmantree ht, int i, int *p1, int *p2);/*选择最小的权值*/④:void createhuffmantree(huffmantree ht) ;/*创建哈夫曼树*/⑤:void huffmancodes(huffmantree ht,huffmancode hcd,char *z) ;/*利用哈夫曼树求哈夫曼编码*/⑥:void bianma(huffmancode hcd);/*对输入的字符进行编码*/⑦:void yima(huffmancode hcd);/*对输入的哈夫曼编码进行译码*/6 数据结构typedef struct{int weight;int lchild,rchild,parent;}htnode;typedef htnode huffmantree[m+1];定义哈夫曼树的结构类型。
typedef struct{char ch;char code[10];} codenode;typedef codenode huffmancode[n+1];定义存储哈夫曼编码的类型。
7 源程序main.cpp#include <iostream>#include <conio.h>#include <stdlib.h>#include"huffman.h"#include<fstream>#include<string.h>using namespace std;int main(){char ch[200];/*用于存储样本*/char z[54];/*用于存储所有字符类别*/huffmantree ht;/*定义一个数组ht,用于存储哈夫曼树*/huffmancode hcd;/*定义一个数组hcd,用于存储哈夫曼编码*/inithuffmantree(ht);/*初始化哈夫曼树*/ifstream infile1("lei.txt");/*lei.txt文件保存了所有字符的总类*/if(!infile1){cout<<"错误:数据文件不能打开!";}for(int i=0; i<54; i++){infile1.get(z[i]);/*把lei.txt的数据读到数组z*/}ifstream infile2("data.txt");/*data.txt文件是统计频数的一个样本,以频数代替权值*/if(!infile2){cout<<"错误:数据文件不能打开!";}for(int i=0; i<200; i++){infile2.get(ch[i]);/*把data.txt数据读到数组ch*/}tongji(ht,ch,z);/*统计权值*/createhuffmantree(ht);/*创建哈夫曼树*/huffmancodes(ht,hcd,z);/*求哈夫曼编码*/bianma(hcd);/*对输入的字符求编码*/cout<<endl;yima(hcd);/*对输入的编码求译码*/}huffman.h#ifndef HUFFMAN_H_INCLUDED#define HUFFMAN_H_INCLUDED#define n 53#define m 2*n-1typedef struct{int weight;int lchild,rchild,parent;}htnode;typedef htnode huffmantree[m+1];/*定义数组存储哈夫曼树*/typedef struct{char ch;char code[10];} codenode;typedef codenode huffmancode[n+1];/*定义数组存储哈夫曼编码*/void inithuffmantree(huffmantree ht);/*初始化哈夫曼树*/void tongji(huffmantree ht,char *ch,char *z);/*统计权值*/void selectmin(huffmantree ht, int i, int *p1, int *p2);/*选择最小的权值*/ void createhuffmantree(huffmantree ht) ;/*创建哈夫曼树*/void huffmancodes(huffmantree ht,huffmancode hcd,char *z) ;/*利用哈夫曼树求哈夫曼编码*/void bianma(huffmancode hcd);/*对输入的字符进行编码*/void yima(huffmancode hcd);/*对输入的哈夫曼编码进行译码*/#endif // HUFFMAN_H_INCLUDEDhuffman.cpp#include<stdio.h>#include<stdlib.h>#include<string.h>#include<conio.h>#include<iostream>#include "huffman.h"using namespace std;void inithuffmantree(huffmantree ht)/*初始化哈夫曼树*/{for(int i=1; i<=m; i++){ht[i].weight=0;ht[i].lchild=0;ht[i].rchild=0;ht[i].parent=0;}}对传入函数的ht进行初始化。
void tongji(huffmantree ht,huffmancode hcd,char *ch,char *z)/*统计权值*/{int l;l=strlen(ch);for(int i=1; i<54; i++)for(int j=1; j<l; j++)if(z[i]==ch[j])ht[i].weight++;}数组ch是从文件data.txt中读取的数据,数组z是从lei.txt中读取的文件,把数组ch与数组z对比,统计每个字符出现的频数,存到ht.weight数组中。
void selectmin(huffmantree ht, int i, int *p1, int *p2)/*创建哈夫曼树*/{int j,min1,min2; /* min1,min2分别是最小权值和次小权值*/min1=min2=1;*p1=*p2=0;for(j=1; j<=i; j++){if(ht[j].parent==0)if(ht[j].weight<min1||min1==1){if(min1!=1){min2=min1;*p2=*p1;}min1=ht[j].weight;*p1=j;}else if(ht[j].weight<min2||min2==1){min2=ht[j].weight;*p2=j;}}}在ht[1..i]中选两个权值最小的根结点,其序号为*p1和*p2,*p1中放权值最小的根结点的序号,*p2中放权值次小的根结点的序号。
void createhuffmantree(huffmantree ht)/*利用哈夫曼树求哈夫曼编码*/{int i,p1,p2;inithuffmantree(ht);for(i=n+1; i<=m; i++){selectmin(ht,i-1,&p1,&p2);ht[p1].parent=ht[p2].parent=i;ht[i].lchild=p1;ht[i].rchild=p2;ht[i].weight=ht[p1].weight+ht[p2].weight;}}在ht[1..i]中选parents为0且weight最小的的两个结点。
其序号为p1,p2. void huffmancodes(huffmantree ht,huffmancode hcd,char *z)/*根据huffman树ht求huffman编码*/{int c,p,i;char cd[n+1];int start;cd[n]='\0';for(i=1; i<54; i++){hcd[i].ch=z[i];start=n;c=i;while((p=ht[c].parent)!=0){cd[--start]=(ht[p].lchild==c)?'0':'1';c=p;}strcpy(hcd[i].code,&cd[start]);}cout<<endl;}数组z是从lei.txt中读取的文件,并把数组lei的值逐个赋给hcd.ch,把编号的哈夫曼编码赋给hcd.code。