实验四--哈夫曼树与哈夫曼编码
数据结构:哈夫曼树和哈夫曼编码
数据结构:哈夫曼树和哈夫曼编码哈夫曼树哈夫曼树是⼀种最优⼆叉树,其定义是:给定n个权值作为n个叶⼦节点,构造⼀棵⼆叉树,若树的带权路径长度达到最⼩,这样的树就达到最优⼆叉树,也就是哈夫曼树,⽰例图如下:基本概念深⼊学习哈夫曼树前,先了解⼀下基本概念,并以上⾯的哈夫曼树图为例路径:树中⼀个结点到另⼀个结点之间的分⽀序列构成两个结点间的路径。
路径长度:路径中分⽀的数⽬,从根结点到第L层结点的路径长度为L-1。
例如100和80的路径长度为1,50和30的路径长度为2。
结点的权:树中结点的数值,例如100,50那些。
结点带权路径长度:根结点到该结点之间的路径长度与该结点的权的乘积。
如结点20的路径长度为3,该结点的带权路径长度为:3*20 = 60。
树的带权路径长度:所有叶⼦结点的带权路径长度之和,记为WPL。
例如上图树的WPL = 1100 + 280 +320 +310 = 350。
带权路径长度⽐较前⾯说到,哈夫曼树是最优⼆叉树,因为符合哈夫曼树特点的树的带权路径长度⼀定是最⼩的,我们将哈夫曼树和普通的⼆叉树做个⽐较,仍以上图为例,上图的哈夫曼树是结点10,20,50,100组成的⼆叉树,WPL是350,⽤这四个结点组成普通的⼆叉树,结果如下:不难计算,该⼆叉树的WPL = 210 + 220 + 250 + 2100 = 360,明显⽐哈夫曼树⼤,当然⼆叉树的组成结果不唯⼀,但WPL⼀定⽐哈夫曼树⼤。
所以说哈夫曼树是最优⼆叉树。
哈夫曼树的构造现在假定有n个权值,设为w1、w2、…、wn,将这n个权值看成是有n棵树的森林,根据最⼩带权路径长度的原则,我们可以按照下⾯步骤来将森林构造成哈夫曼树:1. 在森林中选出根结点的权值最⼩的两棵树进⾏合并,作为⼀棵新树的左、右⼦树,且新树的根结点权值为其左、右⼦树根结点权值之和;2. 从森林中删除选取的两棵树,并将新树加⼊森林;3. 重复1、2步,直到森林中只剩⼀棵树为⽌,该树即为所求得的哈夫曼树。
c语言 哈夫曼树哈夫曼编码
c语言哈夫曼树哈夫曼编码哈夫曼树(Huffman Tree)和哈夫曼编码(Huffman Coding)是由戴维·哈夫曼在1952年为数据压缩应用而发明的。
哈夫曼编码是一种前缀编码,即任何字符的编码都不是另一个字符的编码的前缀。
在编码学中,哈夫曼编码是一种可变长度编码,其中较常见或较频繁的字符使用较短的编码,而较少见或较不频繁的字符使用较长的编码。
这种编码是由哈夫曼树生成的,哈夫曼树是一种特殊的二叉树,其每个节点的权重等于其左子树和右子树的权重之和。
在C语言中实现哈夫曼树和哈夫曼编码可能涉及以下步骤:1、定义哈夫曼树的节点结构。
每个节点可能包括字符,权重(或频率),以及左孩子和右孩子的指针。
ctypedef struct huffman_node {char character;unsigned int frequency;struct huffman_node *left, *right;} huffman_node;2、创建哈夫曼树。
首先,你需要计算每个字符的频率,然后根据这些频率创建一个哈夫曼树。
这个过程可能涉及使用优先队列(最小堆)来找出频率最小的两个节点,然后将它们合并为一个新的节点,新节点的频率是这两个节点的频率之和。
然后,将新节点放回队列中,重复这个过程直到队列中只剩下一个节点,这个节点就是你的哈夫曼树的根节点。
3、使用哈夫曼树生成哈夫曼编码。
从根节点开始,对于每个字符,左子树代表0,右子树代表1。
你可以遍历哈夫曼树,为每个字符生成其对应的哈夫曼编码。
4、实现解码。
给定一个哈夫曼编码,你可以通过遍历哈夫曼树来解码它。
对于每个位,如果是0,你跟随左子树,如果是1,你跟随右子树。
当你到达一个叶节点时,你就找到了对应的字符。
以上只是一个大致的步骤,具体的实现可能会根据你的需求和具体情况有所不同。
二叉树的应用——哈夫曼树和哈夫曼编码
哈夫曼树和哈夫曼编码一、基本概念1.文本由字符构成,字符用编码表示,ASCII编码是一种等长的编码,每个字符的编码长度是相同的。
哈夫曼树和哈夫曼编码使得频率高的字符有较短的编码,使用频率较高的字符有较长的编码。
2.前缀编码字符编码可以有不同的长度,这种编码称为:前缀编码。
3.最小代价的二叉树所有字符都包含在叶结点上,权值大的叶子应该尽量靠近树根,使它的编码尽可能短。
权值小的叶子可以适当离树根远一点。
二、哈夫曼算法1.目的构成一棵最优二叉树,每个结点的权值就是它出现的频率,每棵树的权值由它所有叶结点的出现频率的和组成。
2.一旦构成哈夫曼树,每个字符的哈夫曼编码就是从根到存储该字符的叶结点的路径,如定义左枝为0,右枝为1.三、哈夫曼算法的实现1.原理(1)哈夫曼树类的对象可以接收一组符号以及对应的权值,并返回每个符号对应的哈夫曼编码。
构造函数接收一组代编码的符号以及对应的权值,构造一棵哈夫曼树;返回编码的函数getCode根据保存的哈夫曼树为每个叶结点生成哈夫曼编码。
(2)哈夫曼树可以用一个规模为2n的数组来存储,n为待编码元素的个数。
下标为0的数组元素不用,根存放在下标为1的元素中;叶结点存放在n到2n-1的位置。
每个数组元素保存的信息为:结点的值、权值、父结点、左右儿子的位置。
初始时,将待编码的元素和响应的权值放入数组的第n到2n-1的位置,所有的结点的父结点和左右儿子的位置的字段置为0,表示所有树都只是根结点。
第一次归并,在第n到2n-1的元素中查找权值最小的树,即权值最小且父结点都为0的数组元素,归并后的树的根保存在n-1的元素中,并设置父子关系。
第二次归并,在第n-1到2n-1的元素中查找权值最小的树,归并后的树的根保存在n-2的元素中,并设置父子关系。
最后一次归并的结果放在下标为1的元素中,至此,完成哈夫曼树的生成。
2.代码5-13 哈夫曼树类的定义代码分析template <class Type>//模板类class hfTree{//哈夫曼树类private: //私有成员变量struct Node//数组中的元素类型:结点类{ Type data;//结点值int weight;//结点的权值int parent,left,right;//父结点以及左右儿子的下标地址};Node *elem;//定义一个数组,elem是数组的起始位置,哈夫曼树被保存在一个数组中int length;//数组的规模长度,根据待编码的结点预先静态分配空间public: //公有成员函数struct hfCode{//保存哈夫曼编码的类型Type data;//待编码的字符值string code;//对应的哈夫曼编码};hfTree(const Type*x, const int*w, int size);//构造函数,构造函数接收一组待编码的字符以及对应的权值,构造一棵哈夫曼树void getCode(hfCode result[]);//返回哈夫曼编码的函数~hfTree(){delete []elem;}//析构函数,释放存储空间};template <class Type>hfTree<Type>::hfTree(const Type*v, const int *w, int size)//哈夫曼树的构造函数,有3个参数,一组待编码的符号,符号对应的权值,前面两个数组的数组规模{ const int MAX_INT=32767;int min1,min2;//最小树、次小树的权值,权值最小的两棵树int x, y;//最小树、次小树的下标length=2*size;//待编码的符号有n个,哈夫曼树的规模就为2n-1,由于数组是从0开始,所以数组规模为2n,根结点保存在下标为1的元素中elem=new Node[length];//申请一个保存哈夫曼树的数组for(int i=size;i<length;++i)//for循环为数组赋初值,从第n到2n-1的元素开始{ elem[i].weight=w[i-size];//将待编码的符号对应的权值放到数组的后半部分elem[i].data=v[i-size];//将待编码的符号放到数组的后半部分elem[i].parent=elem[i].left=elem[i].right=0;//将符号的父结点以及左右儿子都设为0,表明它们都是只有根结点的树}for(i=size-1;i>0;--i)//for循环完成size-1次的归并{ min1=min2=MAX_INT;x=y=0;// min1,min2分别保存两棵权值最小的数的权值,x、y分别表示这两棵树的树根在数组中的下标for(int j=i+1;j<length;++j)//找出父结点为0,且权值最小和次小的两棵树,等待归并的两棵树if(elem[j].parent==0)if(elem[j].weight<min1){min2=min1;min1=elem[j].weight;x=y;y=j;}else if(elem[j].weight<min2){min2=elem[j].weight;x=j;}elem[i].weight=min1+min2;//归并这两棵树,形成新树i,i这棵树的权值=min1+min2(分别保存挑选出的两棵权值最小的树的权值)elem[i].left=x;elem[i].right=y;elem[i].parent=0;//将挑选出来的两个结点作为左、右子树,构建一棵新树,i为根结点elem[x].parent=i;elem[y].parent=i;//i是挑选出来的两个结点的父结点 }}5-15 哈夫曼的getCode函数代码分析template <class Type>void hfTree<Type>::getCode(hfCode result[])//哈夫曼树的getCode函数,返回的是一个数组,数组元素类型是hfCode,每一个元素包含待编码的符号和它对应的编码,编码是一个比特串,用字符串类型表示{ int size=length/2;//符号数组规模=哈夫曼数组规模/2int p,s;//s是追溯过程中正在处理结点的下标,p是s的父结点下标for(int i=size;i<length;++i)//读取每一个符号{result[i-size].data=elem[i].data; // result数组中第一个元素符号是哈夫曼数组elem中间的元素符号,因为哈夫曼数组elem包含了元素符号数组和元素符号权值数组,而符号数组规模=权值数组规模,所以哈夫曼数组elem数组是它们的两倍。
哈夫曼树与哈夫曼编码
T->Left = DeleteMin(H); /*从最小堆中删除一个结点,作为新T的左子结点*/
T->Right = DeleteMin(H);
/*从最小堆中删除一个结点,作为新T的右子结点*/
T->Weight = T->Left->Weight+T->Right->Weight; /*计算新权值*/
sp :01
8
4
anl : 11010
10
0
1
nl
18
01
sat
3140
nl
1
4
s Cos3t = 310 + 215
+ 212 + 53
t
4
4
nl
1
0
1
s + 44 + 213 3 + 51
nl
s
= 146
1
3
grade=3
grade=4 grade=5
grade=1 grade=2
效率: 0.05× 3+0.15 ×3+0.4× 2+0.3 ×2+0.1× 2
= 2.2
if( score < 80 ) { if( score < 70 )
if( score < 60 ) grade =1; else grade = 2; else grad=3; }else if( score < 90 ) grade =4; else grade =5;
【分析】 (1)用等长ASCII编码:58 ×8 = 464位; (2)用等长3位编码:58 ×3 = 174位; (3)不等长编码:出现频率高的字符用的编码短些,出现频率低 的字符则可以编码长些?
哈夫曼树及哈夫曼编码的算法实现
哈夫曼树及哈夫曼编码的算法实现1. 哈夫曼树的概念和原理哈夫曼树是一种带权路径长度最短的树,也称最优二叉树。
它是由美国数学家大卫・哈夫曼发明的,用于数据压缩编码中。
哈夫曼树的构建原理是通过贪心算法,将权重较小的节点不断合并,直到所有节点都合并成为一个根节点,形成一棵树。
这样构建的哈夫曼树能够实现数据的高效压缩和解压缩。
2. 哈夫曼编码的概念和作用哈夫曼编码是一种可变长度编码,它根据字符在文本中出现的频率来进行编码,频率越高的字符编码越短,频率越低的字符编码越长。
这种编码方式能够实现数据的高效压缩,减小数据的存储空间,提高数据传输的效率。
3. 哈夫曼树和编码的算法实现在实现哈夫曼树和编码的算法过程中,首先需要统计文本中每个字符出现的频率,并根据频率构建哈夫曼树。
根据哈夫曼树的结构,确定每个字符的哈夫曼编码。
利用哈夫曼编码对文本进行压缩和解压缩。
4. 个人观点和理解哈夫曼树及哈夫曼编码算法是一种非常有效的数据压缩和编码方式,能够在保证数据完整性的前提下,减小数据的存储和传输成本。
在实际应用中,哈夫曼编码被广泛应用于通信领域、数据存储领域以及图像压缩等领域。
通过深入理解和掌握哈夫曼树及哈夫曼编码的算法实现,可以为我们在实际工作中处理大量数据时提供便利和效率。
5. 总结与回顾通过本篇文章的详细讲解,我深入了解了哈夫曼树及哈夫曼编码的算法原理和实现方式,对其在数据处理中的重要性有了更深刻的认识。
掌握了哈夫曼树及哈夫曼编码的算法实现,将为我未来的工作和学习提供更多的帮助和启发。
根据您提供的主题,本篇文章按照从简到繁、由浅入深的方式探讨了哈夫曼树及哈夫曼编码的算法实现。
文章共计超过3000字,深入剖析了哈夫曼树和编码的原理、实现方式以及应用场景,并结合个人观点进行了阐述。
希望本篇文章能够满足您的需求,如有任何修改意见或其他要求,欢迎随时告知。
哈夫曼树和哈夫曼编码是一种十分重要的数据压缩和编码方式,它们在实际的数据处理和传输中发挥着非常重要的作用。
良心出品构造哈夫曼树及哈夫曼编码
《数据结构》实验报告实验名称:构造哈夫曼树及哈夫曼编码计算机科学与技术专业专业:级:计算机科学与技术班姓名:学号:2012/11/22 完成日期:年2012 22 11月日一、问题描述构造一个哈夫曼树,并根据所构造的哈夫曼树求其哈夫曼树的编码;二、需求分析哈夫曼树有叫做最优二叉树,它是指对于一组带有确定的权值的叶节点,构造具有最小的带权路径程度的二叉树。
在数据通信中,经常需要将传送的文字转换成由二进制字符0,1组成的二进制串,称之为编码。
如果在所有的编码中每个字符的编码都一样的长短则有的字符在应用中出现的次数多有的字符在应用中出现的次数少,这样的话有的电文的编码会很长,所以就想用不同长度的编码区代表字符,及在电文中出现的概率大的用短的字符表示,而出现的概率小的用长的字符表示,则得到的电文可能就比较短。
基于以上的需求与要求,就出现了哈夫曼编码。
三、概要设计1、先建立哈夫曼树的结构,即哈夫曼树的构造算法;再建立哈夫曼树编码的结构,即哈夫曼树编码的算法;、 2 、3再带入数据进行验证。
四、详细设计1.、哈夫曼树构造算法的编码:#include<iostream>using namespace std;#define MAXV ALUE 100#define MAXLEAF 30MAXLEAF*2-1 #define MAXNODE#define MAXBIT 10typedef struct{int weifht; //权值int parent; //双亲节点int lchild; //左孩子int rchild; // 右孩子}HNodeType;typedef struct{int bit[MAXBIT];int start;}HCodeType;void HuffmanTree(HNodeType HuffNode[],int n){int i,j,m1,m2,x1,x2;for(i = 0;i < 2*n-1;i++) //对数组进行初始化{HuffNode[i].weifht = 0;HuffNode[i].parent = -1;HuffNode[i].lchild = -1;HuffNode[i].rchild = -1;}输入各个节点的权值for(i = 0;i < n;i++) //{<<endl; ?椼?潣瑵? 输入第个叶节点的权值:cin>>HuffNode[i].weifht; }for(i = 0;i < n-1;i++) //构造哈夫曼树{m1 = MAXV ALUE;m2 = MAXV ALUE;x1 = x2 = 0;for(j = 0;j < n + i;j++) //找出两棵权值最小的树{if(HuffNode[j].weifht < m1&&HuffNode[j].parent == -1){m2 = m1;x2 = x1;m1 = HuffNode[j].weifht;x1 = j;}else if(HuffNode[j].weifht < m2&&HuffNode[j].parent == -1){m2 = HuffNode[j].weifht;x2 = j;}}合并两个子树HuffNode[x1].parent = n + i; //HuffNode[x2].parent = n + i;HuffNode[n+i].weifht = HuffNode[x1].weifht + HuffNode[x2].weifht; HuffNode[n+i].lchild = x1;HuffNode[n+i].rchild = x2;}void HaffmanCode() //哈夫曼编码{HNodeType HuffNode[MAXNODE];HCodeType HuffCode[MAXLEAF],cd;int i,j,c,p,n;潣瑵?输入节点的个数:<<endl; //输入节点的个数cin>>n;HuffmanTree(HuffNode,n);for(i = 0;i < n;i++){cd.start = n - 1;c = i;p = HuffNode[c].parent;while(p != -1){if(HuffNode[p].lchild == c)cd.bit[cd.start] = 0;elsecd.bit[cd.start] = 1;cd.start--;c = p;p = HuffNode[c].parent;}for(j = cd.start+1;j < n;j++)HuffCode[i].bit[j] = cd.bit[j];HuffCode[i].start = cd.start; }<<endl; 哈夫曼编码为:潣瑵?for(i = 0;i < n;i++) {for(j = HuffCode[i].start + 1;j < n;j++)cout<<HuffCode[i].bit[j];cout<<endl;}}int main(void){HaffmanCode();return 0;}五、测试分析结果:输入节点的个数:5输入第0个叶节点的权值:1输入第1个叶节点的权值:2输入第2个叶节点的权值:3输入第3个叶节点的权值:4输入第4个叶节点的权值:5哈夫曼编码为:010011001011Press any key to continue六、总结在本次编写程序的时候开始把哈夫曼树的判断的时候叶节点将(p!= -1)写成了(p!= 1)结果导致不能读出哈夫曼树的编码。
数据结构——哈夫曼(Huffman)树+哈夫曼编码
数据结构——哈夫曼(Huffman)树+哈夫曼编码前天acm实验课,⽼师教了⼏种排序,抓的⼀套题上有⼀个哈夫曼树的题,正好之前离散数学也讲过哈夫曼树,这⾥我就结合课本,整理⼀篇关于哈夫曼树的博客。
哈夫曼树的介绍Huffman Tree,中⽂名是哈夫曼树或霍夫曼树,它是最优⼆叉树。
定义:给定n个权值作为n个叶⼦结点,构造⼀棵⼆叉树,若树的带权路径长度达到最⼩,则这棵树被称为哈夫曼树。
这个定义⾥⾯涉及到了⼏个陌⽣的概念,下⾯就是⼀颗哈夫曼树,我们来看图解答。
(01) 路径和路径长度定义:在⼀棵树中,从⼀个结点往下可以达到的孩⼦或孙⼦结点之间的通路,称为路径。
通路中分⽀的数⽬称为路径长度。
若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
例⼦:100和80的路径长度是1,50和30的路径长度是2,20和10的路径长度是3。
(02) 结点的权及带权路径长度定义:若将树中结点赋给⼀个有着某种含义的数值,则这个数值称为该结点的权。
结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
例⼦:节点20的路径长度是3,它的带权路径长度= 路径长度 * 权 = 3 * 20 = 60。
(03) 树的带权路径长度定义:树的带权路径长度规定为所有叶⼦结点的带权路径长度之和,记为WPL。
例⼦:⽰例中,树的WPL= 1*100 + 2*50 +3*20 + 3*10 = 100 + 100 + 60 + 30 = 290。
⽐较下⾯两棵树上⾯的两棵树都是以{10, 20, 50, 100}为叶⼦节点的树。
左边的树WPL=2*10 + 2*20 + 2*50 + 2*100 = 360 右边的树WPL=350左边的树WPL > 右边的树的WPL。
你也可以计算除上⾯两种⽰例之外的情况,但实际上右边的树就是{10,20,50,100}对应的哈夫曼树。
⾄此,应该堆哈夫曼树的概念有了⼀定的了解了,下⾯看看如何去构造⼀棵哈夫曼树。
实验四 哈夫曼树与哈夫曼编码
实验四哈夫曼树与哈夫曼编码一、实验容[问题描述]已知n个字符在原文中出现的频率,求它们的哈夫曼编码。
[基本要求]1. 初始化:从键盘读入n个字符,以及它们的权值,建立Huffman树。
(具体算法可参见教材P147的算法6.12)2. 编码:根据建立的Huffman树,求每个字符的Huffman编码。
对给定的待编码字符序列进行编码。
二、概要设计算法设计:要是实现哈夫曼树的操作,首先创建一个哈夫曼树,在创建哈夫曼树的时候,对哈夫曼树的叶子和非叶子结点进行初始化,而在建立哈夫曼树时,最难的该是选择权值最小的两个顶点,然后两个结点的权值和作为新的权值,再选择两个权值最小的作为新的两个结点创建一个小的二叉树的子树;创建哈夫曼树后,进行编码,在编码过程中,先找到根,然后遍历,左孩子用0标记,右孩子用1标记,最后将编码好的哈夫曼树进行输出,就可以知道哈夫曼树的编码了。
流程图:算法:模块:在分析了实验要求和算法分析之后,将程序分为四个功能函数,分别如下:首先建立一个哈夫曼树和哈夫曼编码的存储表示:typedef struct {int weight;int parent,lchild,rchild;char elem;}HTNode,*HuffmanTree;//动态分配数组存储赫夫曼树typedef char **HuffmanCode;//动态分配数组存储赫夫曼编码表CrtHuffmanTree(HuffmanTree *ht , int *w, int n):w存放n个字符的权值,构造哈夫曼树HT。
先将叶子初始化,再将非叶子结点初始化,然后构造哈夫曼树。
构造哈夫曼树:for(i=n+1;i<=m;++i){//在HT[1……i]选择parent为0且weight最小的两个Select(HT,i-1,&s1,&s2);HT[s1].parent=i;HT[s2].parent=i;HT[i].lchild=s1;HT[i].rchild=s2;HT[i].weight=HT[s1].weig ht+HT[Select(HuffmanTree &HT,int n,int *s1,int *s2):在所给的权值中,选择出权值最小的两个值。
数据结构实验哈夫曼树及哈夫曼编码c语言
数据结构实验报告:哈夫曼树及哈夫曼编码一、实验目的1. 理解哈夫曼树及哈夫曼编码的概念和原理;2. 掌握C语言中哈夫曼树及哈夫曼编码的实现方法;3. 分析和讨论哈夫曼编码在实际应用中的优势和不足。
二、实验内容和步骤1. 哈夫曼树的构建1.1 通过C语言实现哈夫曼树的构建算法;1.2 输入一组权值,按哈夫曼树构建规则生成哈夫曼树;1.3 输出生成的哈夫曼树结构,并进行可视化展示。
2. 哈夫曼编码的实现2.1 设计哈夫曼编码的实现算法;2.2 对指定字符集进行编码,生成哈夫曼编码表;2.3 对给定字符串进行哈夫曼编码,并输出编码结果。
三、实验过程及结果1. 哈夫曼树的构建在C语言中,通过定义结构体和递归算法实现了哈夫曼树的构建。
根据输入的权值,依次选择权值最小的两个节点构建新的父节点,直至构建完成整棵哈夫曼树。
通过调试和可视化展示,确认了程序正确实现了哈夫曼树的构建。
2. 哈夫曼编码的实现经过分析和设计,利用哈夫曼树的特点实现了哈夫曼编码的算法。
根据生成的哈夫曼树,递归地生成字符对应的哈夫曼编码,并输出编码结果。
对指定的字符串进行了编码测试,验证了哈夫曼编码的正确性和有效性。
四、实验结果分析1. 哈夫曼编码在数据传输和存储中具有较高的压缩效率和可靠性,能够有效减少数据传输量和存储空间;2. 哈夫曼树及哈夫曼编码在通信领域、数据压缩和加密等方面有着广泛的应用和重要意义;3. 在实际应用中,哈夫曼编码的构建和解码算法需要较大的时间和空间复杂度,对于大规模数据的处理存在一定的局限性。
五、实验总结通过本次实验,深入理解了哈夫曼树及哈夫曼编码的理论知识,并掌握了C语言中实现哈夫曼树及哈夫曼编码的方法。
对哈夫曼编码在实际应用中的优势和局限性有了更深入的认识,这对今后的学习和工作有着积极的意义。
六、参考文献1. 《数据结构(C语言版)》,严蔚敏赵现军著,清华大学出版社,2012年;2. 《算法导论》,Thomas H. Cormen 等著,机械工业出版社,2006年。
利用哈夫曼树构造哈夫曼编码
利用哈夫曼树构造哈夫曼编码摘要:1.哈夫曼树的概念及构建方法2.哈夫曼编码的概念及编码步骤3.哈夫曼编码的应用实例正文:一、哈夫曼树的概念及构建方法哈夫曼树(Huffman Tree)是一种用于数据压缩的树形结构,它可以将原始数据转换为对应的编码,从而实现压缩。
哈夫曼树的构建方法如下:1.根据输入数据(字符)的出现概率,将所有字符按照出现概率从大到小的顺序进行排序。
2.取出概率最小的两个字符,将它们作为一棵新树的左右子节点,且概率较小的字符在左侧,概率较大的字符在右侧。
3.递归地重复步骤2,直到只剩下一个字符,这个字符将成为哈夫曼树的根节点。
4.从根节点到每个叶子节点的路径代表一个字符的编码,其中左子节点的边表示0,右子节点的边表示1。
二、哈夫曼编码的概念及编码步骤哈夫曼编码(Huffman Coding)是一种基于哈夫曼树的数据编码方法。
哈夫曼编码的特点是每个字符的编码长度与该字符出现的概率成反比,即出现概率较高的字符对应较短的编码,出现概率较低的字符对应较长的编码。
哈夫曼编码的编码步骤如下:1.根据输入数据(字符)的出现概率,构建一棵哈夫曼树。
2.从哈夫曼树的根节点到每个叶子节点的路径代表一个字符的编码,其中左子节点的边表示0,右子节点的边表示1。
3.将每个字符的编码转换为对应的二进制代码,从而实现数据压缩。
三、哈夫曼编码的应用实例哈夫曼编码广泛应用于数据压缩和传输领域,例如:1.在计算机文件压缩中,利用哈夫曼编码可以将原始数据转换为较短的编码,从而减少存储空间和传输时间。
2.在图像和视频压缩中,哈夫曼编码可以有效地去除冗余信息,降低数据量,从而实现更高的压缩率和更快的传输速度。
哈夫曼树、哈夫曼编码
哈夫曼树、哈夫曼编码哈夫曼树又称最优树(二叉树),是一类带权路径最短的树。
构造这种树的算法最早是由哈夫曼(Huffman)1952年提出,这种树在信息检索中很有用。
结点之间的路径长度:从一个结点到另一个结点之间的分支数目。
树的路径长度:从树的根到树中每一个结点的路径长度之和。
结点的带权路径长度:从该结点到树根之间的路径长度与结点上权的乘积。
树的带权路径长度:树中所有叶子结点的带权路径长度之和,记作:WPL为最小的二叉树就称作最优二叉树或哈夫曼树。
完全二叉树不一定是最优二叉树。
哈夫曼树的构造:(1)根据给定的n个权值{w1,w2,...,w n}构造n棵二叉树的集合F={T1,T2,...,T n},其中Ti中只有一个权值为w i的根结点,左右子树为空;(2)在F中选取两棵根结点的权值为最小的数作为左、右子树以构造一棵新的二叉树,且置新的二叉树的根结点的权值为左、右子树上根结点的权值之和。
(3)将新的二叉树加入到F中,删除原两棵根结点权值最小的树;(4)重复(2)和(3)直到F中只含一棵树为止,这棵树就是哈夫曼树。
例1:例2:结点的存储结构:构造哈夫曼树的算法说明:#define n /* 叶子总数*/#define m 2*n-1 /* 结点总数*/证:由性质3,叶子结点数n0=n2+1,故哈夫曼树结点总数为n0+n2=n0+(n0-1)=2*n0-1例3 在解某些判定问题时,利用哈夫曼树获得最佳判定算法。
(a)WPL=0.05*1+0.15*2+0.4*3+0.3*4+0.1*4=3.15 (b)(c)WPL=0.4*1+0.3*2+0.15*3+0.05*4+0.1*4=2.05 WPL=0.05*3 +0.15*3+0.4*2+0.3*2+0.1*2=2.2哈夫曼编码从哈夫曼树根结点开始,对左子树分配代码“0”,右子树分配代码“1”,一直到达叶子结点为止,然后将从树根沿每条路径到达叶子结点的代码排列起来,便得到了哈夫曼编码。
哈夫曼树与哈夫曼树编码实验原理
哈夫曼树与哈夫曼树编码实验原理哈夫曼树(Huffman Tree)是一种用于数据压缩的树形数据结构。
它的主要原理是通过构建一个最优的二叉树来实现编码和解码的过程。
以下是哈夫曼树和哈夫曼编码的实验原理:1. 构建哈夫曼树:- 给定一组需要进行编码的字符及其出现频率。
通常,这个频率信息可以通过统计字符在原始数据中的出现次数来得到。
- 创建一个叶节点集合,每个叶节点包含一个字符及其对应的频率。
- 从叶节点集合中选择两个频率最低的节点作为左右子节点,创建一个新的父节点。
父节点的频率等于左右子节点频率的和。
- 将新创建的父节点插入到叶节点集合中,并将原来的两个子节点从集合中删除。
- 重复上述步骤,直到叶节点集合中只剩下一个节点,即根节点,这个节点就是哈夫曼树的根节点。
2. 构建哈夫曼编码:- 从哈夫曼树的根节点开始,沿着左子树走一步就表示编码的0,沿着右子树走一步表示编码的1。
- 遍历哈夫曼树的每个叶节点,记录从根节点到叶节点的路径,得到每个字符对应的编码。
由于哈夫曼树的构建过程中,频率较高的字符在树中路径较短,频率较低的字符在树中路径较长,因此哈夫曼编码是一种前缀编码,即没有任何一个字符的编码是其他字符编码的前缀。
3. 进行数据压缩:- 将原始数据中的每个字符替换为其对应的哈夫曼编码。
- 将替换后的编码串连接起来,形成压缩后的数据。
4. 进行数据解压缩:- 使用相同的哈夫曼树,从根节点开始,按照压缩数据中的每个0或1进行遍历。
- 当遇到叶节点时,就找到了一个字符,将其输出,并从根节点重新开始遍历。
- 继续按照压缩数据的编码进行遍历,直到所有的编码都解压为字符。
通过构建最优的哈夫曼树和对应的编码表,可以实现高效的数据压缩和解压缩。
频率较高的字符使用较短的编码,从而达到减小数据大小的目的。
而频率较低的字符使用较长的编码,由于其出现频率较低,整体数据大小的增加也相对较小。
综合实验四 哈夫曼码编、译码器的实现
综合实验四哈夫曼码编、译码器的实现一、实验名称哈夫曼码编、译码器的实现二、实验目的1、熟练哈夫曼树的定义,掌握构造哈夫曼树的方法。
2、掌握哈夫曼编码和译码方法。
3、掌握文本文件的读写方法。
三、实验内容1、实验内容:利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编码、译码系统。
试为这样的信息收发站写一个哈夫曼码的编码、译码系统。
一个完整的系统应以下功能:(1) 从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存放在文件hfmTree中。
(2) 利用已建立好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran 中的正文进行编码,然后将结果代码存(传输)到文件CodeFile中.(3) 译码(Decoding)。
利用已建好的哈夫曼树,对传输到达的CodeFile中的数据代码进行译码,将译码结果存入文件TextFile。
(4) 将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrin中。
(5) 打印印哈夫曼树(TreePrinting)。
将已在内存中的哈夫曼树以直观的方式(树或凹入表的形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
(6)数据结构设计根据下面给出的存储结构定义typedef struct // 定义哈夫曼树中每个结点结构体类型{char ch; //结点字符信息int weight; // 定义一个整型权值变量int lchild; // 定义左、右孩子及双亲指针int rchild;int parent;} HTNode;typedef HTNode HFMT[MAXLEN]; //用户自定义HFMT数组类型typedef char** HfCode;//动态分配字符数组存储哈夫曼编码表(7)基本操作的函数设计void InitHFMT(HFMT T);//初始化哈夫曼树void InputWeight(HFMT T,char* weightFile);// 输入权值void SelectMin(HFMT T,int i,int *p1,int *p2);//选择所有结点中较小的结点void CreatHFMT(HFMT T);// 构造哈夫曼树,T[2*n-1]为其根结点void PrintHFMT (HFMT T);// 输出向量状态表void printHfCode(HfCode hc);//输出字符的哈夫曼编码序列HfCode hfEnCoding(HFMT T);//利用构成的哈夫曼树生成字符的编码void print_HuffmanTree(HFMT HT,int t,int i)//按树形形态输出哈夫曼树的形态void Encoder(char* original,char* codeFile,HfCode hc,HFMT HT);//利用已建好的哈夫曼树,对original文件中要传输的原始数据进行编码,//将编码结果存入文件codeFile中void Decoder(char* codeFile ,char* textFile,HFMT HT);//利用已建好的哈夫曼树,对传输到达的codeFile中的数据代码进行译码,//将译码结果存入文件textFile中2、实验要求(1)、用C语言编程实现上述实验内容中的结构定义和算法。
数据结构哈夫曼树和哈夫曼编码
最优二叉树的定义
结点的路径长度定义为:
从根结点到该结点的路径上分支的数目。
树的路径长度定义为:
A
树中每个结点的路径长度之和。 B C E
D
树的路径长度为5
最优二叉树的定义
树的带权路径长度定义为:
哈夫曼树与哈夫曼编码
1.最优二叉树的定义 2.如何构造最优二叉树 3.哈夫曼编码
编码
假设要将一段文字“ABAADBCACB”由甲方传给乙方
编码:用二进制数表示字符
ABCD
00 01 10 11
特点:等长编码
ABAADBCACB 00010000110110001001 总的编码长度是20位
前缀编码
哈夫曼树
2.在 F 中选取其根结点的权值为最小的两 棵二叉树,分别作为左、右子树构造一棵新的 二叉树,并置这棵新的二叉树根结点的权值为 其左、右子树根结点的权值之和;
哈夫曼树
3.从F中删去这两棵树,同时将刚生成的新 树加入到F中;
4.重复 (2) 和 (3) 两步,直至 F 中只含
一棵树为止。
哈夫曼树
1) 5
6
2
2) 6
9
7
9
7
7
3) 9
2
5
7
13
6
7
2
5
哈夫曼树
4)
13
6
7
2
5
16
7
9
5)பைடு நூலகம்
29
13
16
6
7
7
9
2
实验四 哈弗曼编码
实验四、哈夫曼编码实验目的掌握哈夫曼编码的原理,并编出最优编码实验环境C语言读写文件实验内容先根据位权构造一颗哈夫曼树,测试数据0.05 0.1 0.15 0.2 0.25 0.25,再从叶子结点到根结点编码。
源代码实验结果实验总结源代码#include <stdio.h>#include <string.h>#include<stdlib.h>#define N 50 /*叶子结点数*/#define M 2*N-1 /*树中结点总数*/typedef struct{char data[5]; /*结点值*/float weight; /*权重*/float parent; /*双亲结点*/float lchild; /*左孩子结点*/float rchild; /*右孩子结点*/} HTNode;typedef struct{char cd[N]; /*存放哈夫曼码*/int start;} HCode;void CreateHT(HTNode ht[],int n){int i,k,lnode,rnode;float min1,min2;for (i=0;i<2*n-1;i++) /*所有结点的相关域置初值-1*/ht[i].parent=ht[i].lchild=ht[i].rchild=-1;for (i=n;i<2*n-1;i++) /*构造哈夫曼树*/{min1=min2=32767; /*lnode和rnode为最小权重的两个结点位置*/ lnode=rnode=-1;for (k=0;k<=i-1;k++)if (ht[k].parent==-1) /*只在尚未构造二叉树的结点中查找*/{if (ht[k].weight<min1){min2=min1;rnode=lnode;min1=ht[k].weight;lnode=k;}else if (ht[k].weight<min2){min2=ht[k].weight;rnode=k;}}ht[lnode].parent=i;ht[rnode].parent=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,f,c;HCode hc;for (i=0;i<n;i++) /*根据哈夫曼树求哈夫曼编码*/ {hc.start=n;c=i;f=ht[i].parent;while (f!=-1) /*循序直到树根结点*/{if (ht[f].lchild==c) /*处理左孩子结点*/hc.cd[hc.start--]='0';else /*处理右孩子结点*/hc.cd[hc.start--]='1';c=f;f=ht[f].parent;}hc.start++; /*start指向哈夫曼编码最开始字符*/ hcd[i]=hc;}}void main(){int n=6,i,k;float sum=0,m=0,j;float fnum[6];HTNode ht[M];HCode hcd[N];char *str[]={"a0","a1","a2","a3","a4","a5"};//float fnum[]={0.05,0.1,0.15,0.2,0.25,0.25};FILE *fp;if((fp=fopen("H:\\study\\C++\\file\\hafuman.txt","r+"))==NULL) {printf("不能打开文件!\n");exit(1);}for(i=0;i<n;i++)fscanf(fp,"%f",&fnum[i]);//原始文件的输出fseek(fp,0,2);//for(i=0;i<n;i++)//{// printf("%5.2f ",fnum[i]);//}//printf("\n");printf("\n赋值给字符:");fprintf(fp,"\n赋值给字符:");for(i=0;i<n;i++){printf("\n%s=%.2f ",str[i],fnum[i]);fprintf(fp,"\n%s=%.2f ",str[i],fnum[i]);}for (i=0;i<n;i++){strcpy(ht[i].data,str[i]);ht[i].weight=fnum[i];}printf("\n");CreateHT(ht,n);CreateHCode(ht,hcd,n);// DispHCode(ht,hcd,n);printf("输出哈夫曼编码:\n"); /*输出哈夫曼编码*/fprintf(fp,"\n输出哈夫曼编码:\n");for (i=0;i<n;i++){j=0;printf(" %s:\t",ht[i].data);fprintf(fp," %s:\t",ht[i].data);for (k=hcd[i].start;k<=n;k++){printf("%c",hcd[i].cd[k]);fprintf(fp,"%c",hcd[i].cd[k]);j++;}m+=ht[i].weight;sum+=ht[i].weight*j;printf("\n");fprintf(fp,"\n");}printf("\n 平均长度=%.2f\n",sum/m);fprintf(fp,"\n 平均长度=%.2f\n",sum/m);printf("\n");fprintf(fp,"\n");fclose(fp);}测试结果:0.05 0.10 0.15 0.2 0.25 0.25(最开始写入的数据)赋值给字符:a0=0.05a1=0.10a2=0.15a3=0.20a4=0.25a5=0.25输出哈夫曼编码:a0: 1110a1: 1111a2: 110a3: 00a4: 01a5: 10平均长度=2.45。
实验四二叉树的应用-哈夫曼编码(实验报告)
哈夫曼编码实验四二叉树的应用-哈夫曼编码一、实验目的1.在二叉树基本操作的基础上,掌握对二叉树的一些其它操作的具体实现方法。
2.掌握构造哈夫曼树以及哈夫曼编码的方法。
二、实验内容哈夫曼树和哈夫曼编码:从终端输入若干个字符,统计字符出现的频率,将字符出现的频率作为结点的权值,建立哈夫曼树,然后对各字符进行哈夫曼编码。
最后打印哈夫曼树和对应的哈夫曼编码。
设计要求:⑴哈夫曼殊和哈夫曼编码的存储表示参考教材事例⑵在程序中构造四个子程序为①int freqchar(char *text, HTree *t) /*统计字符出现的频率*/②int createhtree(HTree *t) /*根据字符出现的频率建立哈夫曼树*/③void coding(HTree *t,int head_i,char *code)/*对哈夫曼树进行编码*/④void printhtree(HTree *t,int head_i,int deep,int* path)/*中序打印树*/三、实验步骤㈠、数据结构与核心算法的设计描述# include <stdio.h># include <malloc.h># include <iostream.h># include <conio.h># include <string.h># define MAX_LENGTH 100typedef char **HuffmanCode;typedef struct //define structure HuffmanTree {unsigned int weight;unsigned int parent,lchild,rchild;}HTNode,*HuffmanTree;㈡、函数调用及主函数设计④㈢程序调试及运行结果分析㈣实验总结哈弗曼编码输入抽象数据类型,不易掌握,需要慢慢修改。
哈夫曼树和哈夫曼编码
哈夫曼树和哈夫曼编码当树中的节点被赋予一个表示某种意义的数值,我们称之为该节点的权。
从树的根节点到任意节点的路径长度(经过的边数)与该节点上权值的乘积称为该节点的带权路径长度。
树中所有叶节点的带权路径长度之和称为该树的带权路径长度(WPL)。
当带权路径长度最小的二叉树被称为哈夫曼树,也成为最优二叉树。
如下图所示,有三课二叉树,每个树都有四个叶子节点a,b,c,d,分别取带权7,5,2,4。
他们的带权路径长度分别为(a) WPL = 7x2+5x2+2x2+4x2=36(b) WPL = 2X1+4X2+7X3+5X3 = 46(c) WPL = 7x1+5x2+2x3+4x3 = 35节点如果像c中的方式分布的话,WPL能取最小值(可证明),我们称为哈夫曼树。
哈夫曼树构造哈夫曼树在构造时每次从备选节点中挑出两个权值最小的节点进行构造,每次构造完成后会生成新的节点,将构造的节点从备选节点中删除并将新产生的节点加入到备选节点中。
新产生的节点权值为参与构造的两个节点权值之和。
举例如下:•备选节点为a,b,c,d,权值分别为7,5,2,4•选出c和d进行构造(权值最小),生成新节点为e(权值为6),备选节点变为7,5,6•选出b和e进行构造,生成新节点f(权值为11),备选节点为7,11 •将最后的7和11节点进行构造,最后生成如图所示的哈夫曼树哈夫曼树应用在处理字符串序列时,如果对每个字符串采用相同的二进制位来表示,则称这种编码方式为定长编码。
若允许对不同的字符采用不等长的二进制位进行表示,那么这种方式称为可变长编码。
可变长编码其特点是对使用频率高的字符采用短编码,而对使用频率低的字符则采用长编码的方式。
这样我们就可以减少数据的存储空间,从而起到压缩数据的效果。
而通过哈夫曼树形成的哈夫曼编码是一种的有效的数据压缩编码。
如果没有一个编码是另一个编码的前缀,则称这样的编码为前缀编码。
如0,101和100是前缀编码。
哈夫曼(huffman)树和哈夫曼编码
哈夫曼(huffman)树和哈夫曼编码讨论QQ群:待定哈夫曼树哈夫曼树也叫最优二叉树(哈夫曼树)问题:什么是哈夫曼树?例:将学生的百分制成绩转换为五分制成绩:≥90 分: A,80~89分: B,70~79分: C,60~69分: D,<60分: E。
if (a < 60){b = 'E';}else if (a < 70) {b = ‘D’;}else if (a<80) {b = ‘C’;}else if (a<90){b = ‘B’;}else {b = ‘A’;}判别树:用于描述分类过程的二叉树。
如果每次输入量都很大,那么应该考虑程序运行的时间如果学生的总成绩数据有10000条,则5%的数据需1 次比较,15%的数据需 2 次比较,40%的数据需 3 次比较,40%的数据需 4 次比较,因此 10000 个数据比较的次数为: 10000 (5%+2×15%+3×40%+4×40%)=31500次此种形状的二叉树,需要的比较次数是:10000 (3×20%+2×80%)=22000次,显然:两种判别树的效率是不一样的。
问题:能不能找到一种效率最高的判别树呢?那就是哈夫曼树回忆树的基本概念和术语路径:若树中存在一个结点序列k1,k2,…,kj,使得ki是ki+1的双亲,则称该结点序列是从k1到kj的一条路径。
路径长度:等于路径上的结点数减1。
结点的权:在许多应用中,常常将树中的结点赋予一个有意义的数,称为该结点的权。
结点的带权路径长度:是指该结点到树根之间的路径长度与该结点上权的乘积。
树的带权路径长度:树中所有叶子结点的带权路径长度之和,通常记作:其中,n表示叶子结点的数目,wi和li分别表示叶子结点ki的权值和树根结点到叶子结点ki之间的路径长度。
赫夫曼树(哈夫曼树,huffman树)定义:在权为w1,w2,…,wn的n个叶子结点的所有二叉树中,带权路径长度WPL最小的二叉树称为赫夫曼树或最优二叉树。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验四哈夫曼树与哈夫曼编码一、实验目的1、使学生熟练掌握哈夫曼树的生成算法。
2、熟练掌握哈夫曼编码的方法。
二、实验内容[问题描述]已知n个字符在原文中出现的频率,求它们的哈夫曼编码。
[基本要求]1. 初始化:从键盘读入n个字符,以及它们的权值,建立Huffman树。
(具体算法可参见教材P147的算法6.12)2. 编码:根据建立的Huffman树,求每个字符的Huffman 编码。
对给定的待编码字符序列进行编码。
[选作内容]1. 译码:利用已经建立好的Huffman树,对上面的编码结果译码。
译码的过程是分解电文中的字符串,从根结点出发,按字符’0’和’1’确定找左孩子或右孩子,直至叶结点,便求得该子串相应的字符。
4. 打印Huffman树。
[测试数据]利用教材P.148 例6-2中的数据调试程序。
可设8种符号分别为A,B,C,D,E,F,G,H。
编/译码序列为“CFBABBFHGH”(也可自己设定数据进行测试)。
三、算法设计1、主要思想:******************赫夫曼树的构造**********************(1) 由给定的n 个权值{w1, w2, …, wn},构造具有n 棵二叉树的森林F ={T1, T2, …, Tn },其中每棵二叉树Ti 只有一个带权为wi 的根结点, 其左、右子树均为空。
(2) 在F 中选取两棵根结点的权值最小的二叉树, 作为左、右子树构造一棵新的二叉树。
置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。
(3)在F 中删去这两棵二叉树, 把新的二叉树加入F。
(4)重复(2)和(3), 直到F 中仅剩下一棵树为止。
****************************霍夫曼编码*****************************主要用途是实现数据压缩。
由于赫夫曼树中没有度为1的节点,则一棵有n个叶子结点的赫夫曼树共有2n-1个结点,可以存储在一个大小为2n-1的一维数组中。
由于在构成赫夫曼树之后,为求编码需从叶子结点出发走一条从叶子到根的路径;而为译码需从根出发走一条从根到叶子的路径。
则对每个结点而言,既须知双亲的信息,又需知孩子结点的信息。
2、本程序包含三个模块1)主函数Int main(){ 先输入结点总数;分别输入各个结点;调用建立哈夫曼树函数;调用编码函数读入建立的哈夫曼树进行编码}3、元素类型、结点类型和指针类型typedef struct //定义新数据类型即结点结构{int weight; //权重域int parent,lchild,rchild; //指针域}htnode; //结点类型标识符//typedef htnode * huffmanstree; //定义哈弗曼数类型htnode ht[maxnodenumber];//定义三叉链表存储数组typedef struct //定义保存一个叶子节点哈弗曼编码的结构{ int bit[maxbit]; //定义一维数组为编码域int start; //定义位置域}hcnodetype; //定义编码类型4、主函数和其他函数清单1)Int main(){ 先输入结点总数;分别输入各个结点;调用建立哈夫曼树函数;调用编码函数读入建立的哈夫曼树进行编码}2)htnode * creatstree(int n) ——建立哈夫曼树算法实现函数3)void getstree(htnode * ht,int n) ——哈夫曼编码算法及打印函数的实现四、调试分析输入结点总数分别输入各个结点赫夫曼的编码五、总结本次实验电子报告中我原来打算加上各函数的简单流程图,但是由于我处理图形方面还比较不熟练,画了三四个小时也不太满意,所以索性将几个小时的努力通过del键结束了,所以这次报告不太令人满意,我将在以后的报告中加上示意图,多学习同学优秀的地方.也会在以后的学习过程中要尽量考虑周全,使程序更有实用价值,提高编程能力。
我更加认识到自己动手的重要性,因为问题看起来很简单,但是等到亲自去实践时,你会发现出现很多问题。
正是通过不断的发现问题、解决问题,我们才更加深刻的领悟到为核心,进而更好的掌握所学的知识;其次,我认识到了自己不明白的地方一定要向老师请教,老师的点拨,让人豁然开朗,有助于我们更好的理解和掌握。
最后,我理解栈的顺序结构,实现了一些基本操作,掌握了栈的先进后出的特点,并且能运用这一点解决实际问题。
六、源代码#include<stdio.h>#include<iostream.h>#include<malloc.h>#define maxvalue 10000 //定义最大权值常量#define maxnodenumber 100 //定义节点最大数#define maxbit 10 //定义哈弗曼编码最大长度typedef struct //定义新数据类型即节点结构{int weight; //权重域?int parent,lchild,rchild; //指针域}htnode; //节点类型标识符//typedef htnode * huffmanstree; //定义哈弗曼数类型htnode ht[maxnodenumber];//定义三叉链表存储数组typedef struct //定义保存一个叶子节点哈弗曼编码的结构{ int bit[maxbit]; //定义一维数组为编码域int start; //定义位置域}hcnodetype; //定义编码类型htnode * creatstree(int n)//huffmanstree creatstree(int n) //建立哈夫曼树算法实现函数{ int i,j,m1,m2,k1,k2; //局部变量for(i=0;i<2*n-1;i++)//初始化各节点{ ht[i].weight=0; //权重初始化为0ht[i].parent=-1; //根节点和给左右孩子初始化为-1ht[i].lchild=-1;ht[i].rchild=-1;}for(i=0;i<n;i++)//权重赋初值,由用户输入{ scanf("%d",&ht[i].weight);}for(i=0;i<n-1;i++) //生成新节点构造哈夫曼树{ m1=maxvalue; //预置最小权值变量为最大权值m2=maxvalue; //预置次小权值变量为最大权值k1=0;//预置最小权值节点位置为下标为0处k2=0;//预置次小权值节点位置为下标为0处for(j=0;j<n+i;j++)//循环找出每趟最下权值和所在位置?if(ht[j].parent==-1&&ht[j].weight<m1){m2=m1;k2=k1;m1=ht[j].weight;k1=j;}else //当小于当前次小m2则更新m2及其位置if(ht[j].parent==-1&&ht[j].weight<m2){m2=ht[j].weight;k2=j;}ht[k1].parent=n+i;//修改最小权值节点的双亲为刚生成的新节点ht[k2].parent=n+i;//修改次小权值节点的双亲为刚生成的新节点ht[n+i].weight=ht[k1].weight+ht[k2].weight; //将新生成的权重值填入新的根节点ht[n+i].lchild=k1; //新生节点左孩子指向k1ht[n+i].rchild=k2; //新生节点右孩子指向k2}return ht; //返回哈夫曼树指针?}void getstree(htnode * ht,int n) //哈夫曼编码算法及打印函数的实现?{ int i,j,c,p; //局部变量的定义hcnodetype cd[maxnodenumber]; //定义存储哈夫曼编码的数组for(i=0;i<n;i++) //循环控制对每一个节点进行编码{ c=i; //为编码各节点初始化c和jj=maxbit;do{ j--;//j指向bit中存放编码为的正确位置p=ht[c].parent; //p指向c的双亲节点if(ht[p].lchild==c)//如果c是p的左孩子cd[i].bit[j]=0;//编码为赋值0else//否则即c是p的右孩子cd[i].bit[j]=1;//编码赋值1c=p;//更新当前指针,为下一节点编码做准备}while(ht[p].parent!=-1);//判断是否编码结束即循环至最终根节点cd[i].start=j;//编码完成,记下编码开始位置}for(i=0;i<n;i++) //循环打印各节点哈夫曼编码{ for(j=cd[i].start;j<maxbit;j++)//循环逐一输出printf("%d",cd[i].bit[j]);printf("\n");//每输出一编码后换行}}int main() //主函数{ int n;printf("***************欢迎欣赏哈夫曼树***************:");cout<<endl;printf("请输入节点数:"); //用户输入节点数scanf("%d",&n);cout<<endl;cout<<"分别输入哈夫曼树的各个节点:"<<endl;htnode * p; //huffmanstree p //定义哈夫曼树类型pp=(htnode * )malloc(sizeof(htnode *));//p=(huffmanstree)malloc(sizeof(huffmanstree))//分配内存空间p=creatstree(n);//调用建立哈夫曼树函数赋返回值给pcout<<"哈夫曼树的编码为:"<<endl;getstree(p,n); //调用编码函数读入建立的哈夫曼树p进行编码return 0;}THANKS !!!致力为企业和个人提供合同协议,策划案计划书,学习课件等等打造全网一站式需求欢迎您的下载,资料仅供参考。