哈夫曼树学习笔记:
一、何为哈夫曼树
给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度(WPL)达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树。特点:权值较大的结点离根较近。
二、哈夫曼树有什么用
计算机中实际应用多为哈夫曼编码。哈夫曼编码是一种用来无损压缩数据的方式,主要是通过计算一篇文章中一个字符的出现概率(英文文章中e出现的最多而z最小),使出现次数多的字符用较少的编码,出现少的用较长的编码。比如字符e用哈夫曼编码进行编写就仅为1位,而字符z却需要25位,虽然字符z的编码长度长了2倍有余(经哈夫曼编码之前每个字符的编码长度为8位即1字节),但其因出现概率问题,哈夫曼编码仍为一种高效无损的编码(经哈夫曼编码后每句不同的话的编码都是不同的)
三、例题
1.哈夫曼树
题目描述
哈夫曼树,第一行输入一个数n,表示叶结点的个数。需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出所有结点的值与权值的乘积之和。
输入描述 输入有多组数据。
每组第一行输入一个数n,接着输入n个叶节点(叶节点权值不超过100,2<=n<=1000)。
输入样例
2 2 8 3 5 11 30
输出样例
10 62
分析
这道题就是让我们构造一个哈夫曼树,这里我为大家介绍一种构造方法,我们看“何为哈夫曼树”中的这一句话“特点:权值较大的结点离根较近。”,经这句话我们易得另一个结论权值较小的离根节点远这样我们就可以先从小的开始构造,先从一堆叶子节点中选取最小的两个,将他们的和作为根,最小的两个叶子做小子树,构建出一个子树,再将子树的根作为叶子,重复此过程,即可得一颗哈夫曼树,此题我们不需构建哈夫曼树,只用求所有结点的值与权值的乘积之和,所以我们只需在过程中将“最小的两个叶子”累加求和即可得出结果,而我们重新看一遍过程,我们发现我们每构建一棵子树都需要重新取最小值,但我们不能每次都排序(会TLE),那有没有一种结构可以获取一个数据就重新排好序?答案是有的,那就是堆,但是我们如果手写堆没优化的也要30余行,且其插入、删除、查询都要O(log2n)的时间,那太慢了,所以我介绍一个好东西——优先队列(priority_queue)STL是C++中永远的朋友,用它就可以实现对堆的操作,具体用法见下一篇文章,话不多数,上代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 ll n,t,sum,a,b; 5 priority_queue< int,vector<int>,greater<int> > q; 6 int main(){ 7 while(cin>>n){ 8 sum=0; 9 for(int i=0;i<n;i++){ 10 cin>>t; 11 q.push(t); 12 } 13 while(q.size()>1){ 14 a=q.top(); 15 q.pop(); 16 b=q.top(); 17 q.pop(); 18 //取最小的两个叶子节点 19 sum+=a+b;//计算结点的值与权值的乘积之和 20 q.push(a+b); 21 } 22 if(q.size())q.pop();//多组输入记得清空 23 cout<<sum<<endl; 24 } 25 return 0; 26 }
如有错误,敬请指正
标签:编码,结点,哈夫曼,字符,笔记,学习,权值,输入 来源: https://www.cnblogs.com/2009cqr/p/16475826.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。