哈夫曼树

计算机基础(6)

∥☆過路亽.° 提交于 2020-02-16 21:20:11
下面是莫尔斯编码的 示例 ,大家把 1 看作是短点(嘀),把 11 看作是长点(嗒)即可。 莫尔斯编码一般把文本中出现最高频率的字符用 短编码 来表示。如表所示,假如表示短点的位是 1,表示长点的位是 11 的话,那么 E(嘀)这一数据的字符就可以用 1 来表示,C(滴答滴答)就可以用 9 位的 110101101 来表示。在实际的莫尔斯编码中,如果短点的长度是 1 ,长点的长度就是 3,短点和长点的间隔就是1。这里的长度指的就是声音的长度。比如我们想用上面的 AAAAAABBCDDEEEEEF 例子来用莫尔斯编码重写,在莫尔斯曼编码中,各个字符之间需要加入表示时间间隔的符号。这里我们用 00 加以区分。 所以,AAAAAABBCDDEEEEEF 这个文本就变为了 A * 6 次 + B * 2次 + C * 1次 + D * 2次 + E * 5次 + F * 1次 + 字符间隔 * 16 = 4 位 * 6次 + 8 位 * 2次 + 9 位 * 1 次 + 6位 * 2次 + 1位 * 5次 + 8 位 * 1次 + 2位 * 16次 = 106位 = 14字节。 所以使用莫尔斯电码的压缩比为 14 / 17 = 82% 。效率并不太突出。 用二叉树实现哈夫曼算法 刚才已经提到,莫尔斯编码是根据日常文本中各字符的出现频率来决定表示各字符的编码数据长度的。不过,在该编码体系中

哈夫曼树的带权路径长度 = 非叶子结点的权值之和 怎么理解?

我们两清 提交于 2020-02-12 09:57:43
先看一个题目: 题目描述 哈夫曼树,第一行输入一个数n,表示叶结点的个数。需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出哈夫曼树的带权路径长度。 输入描述: 输入有多组数据。 每组第一行输入一个数n,接着输入n个叶节点(叶节点权值不超过100,2<=n<=1000)。 输出描述: 输出带权路径长度。 示例1 输入 5 1 2 2 5 9 输出 37 这题用到一个结论: 哈夫曼树的带权路径长度 = 非叶子结点的权值之和 一个便于理解这个结论的思路如下: 1 #include <iostream> 2 #include <string> 3 #include <queue> 4 5 using namespace std; 6 7 int a[1010]; 8 9 int main() 10 { 11 12 int n; 13 while(cin >> n) 14 { 15 priority_queue<int, vector<int>, greater<int> > q; 16 for(int i = 0; i < n; ++i) 17 { 18 cin >> a[i]; 19 q.push(a[i]); 20 } 21 22 int ans = 0; 23 while(q.size() > 1) 24 { 25 int a = q

Codeforces 37 C Old Berland Language

…衆ロ難τιáo~ 提交于 2020-02-02 03:22:34
题意 构造出指定长度的n个01字串,每个字串不能是其他字串的子串 算法:用DFS模拟 “不能是其他字串的子串”用哈夫曼编码方式编的字串符合这个规则,且会“最短”,本题无需最短,只需满足前一个条件即可。 哈夫曼编码需要构造哈夫曼树(不过此题不需要构造树),然后对哈夫曼树的所有指向左子树的边编码为0,右为1,以此解决“不能是其他字串的子串”问题 因此我们本题可以假设哈夫曼树已经构造完毕,然后用dfs去寻找01字串的编码,当编码长度是题目给定的长度值时就表示构造成功了一个长度 因为dfs也是逐步构造的,长度信息也是逐步增加的,因此需要将原始长度序列升序排序 # include <cstdio> # include <string> # include <iostream> # include <algorithm> using namespace std ; const int maxn = 1000 + 5 ; struct node { int len , id ; string s ; } ; node a [ maxn ] ; int n , cnt = 0 , flag = 0 ; bool cmp1 ( node a , node b ) { return a . len < b . len ; } bool cmp2 ( node a , node b ) { return

哈夫曼树的建立——从一个数组中得到最小数和次小数谈起

笑着哭i 提交于 2020-02-01 06:15:47
👴周末两天也算就看了哈夫曼树和编码问题了,进度巨慢,还有一个骑士周游算法跑到现在还没出结果。。。。。 趁热打铁,把自己的一些心得分享给大家。 重点在后面。。。 话不多说 都在代码注释里了 这个是只操作整数数组 # include <iostream> # define N 10 using namespace std ; void Find_Min_SubMin_Nums ( int data [ ] , int n ) { int min1 , min2 ; //min1 是最小数 min2 是次小数d min1 = min2 = 30000 ; //先让这两个数取得尽量大 for ( int i = 0 ; i < n ; i ++ ) { if ( data [ i ] < min1 ) //数组中某一数据比最小值还小? 那么最小值应该是它 //之前的最小值暂时算是第二小的数 所以可以把之前的最小值给次小值 { min2 = min1 ; min1 = data [ i ] ; } //找到了最小数 就没必要关心次小数了 因为当前的min1 min2 都取到了最小 else if ( data [ i ] < min2 ) //此时的情况是说,扫描到的数字 比最小值大 但是比次小值小 //这好办 直接把次小值替换 min2 = data [ i ] ; } //如此循环下去

oj --哈夫曼树-求带权路径长度

我是研究僧i 提交于 2020-01-31 07:04:45
题目所描述的有点问题,其实是叶节点的路径与权值乘积之和,即带权路径长度! 用到了c++中小顶堆的创建方法,优先队列。 定义:priority_queue<Type, Container, Functional> Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆 还利用到: 若定义每个结点都有值,为其子女的值之和,那么除了根结点外所有结点之和恰好等于带权路径长度 ,按层级累加的规律不难理解叶子节点的值也是“乘了好多倍” # include <iostream> # include <stdio.h> # include <queue> using namespace std ; priority_queue < int , vector < int > , greater < int > > Q ; int main ( ) { int N ; while ( scanf ( "%d" , & N ) != EOF ) { while ( ! Q . empty ( ) ) Q . pop ( ) ; for

霍夫曼树

女生的网名这么多〃 提交于 2020-01-27 00:38:18
定义 霍夫曼树:假设有n个权值,可以构造一颗具有n个叶子节点的二叉树,其中带权路径长度WPL最小的二叉树称作最优二叉树,也叫霍夫曼树。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。 构造过程 假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为: (1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点); (2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和; (3)从森林中删除选取的两棵树,并将新树加入森林; (4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。 前缀编码 前缀编码 是指对字符集进行编码时,要求字符集中任一字符的编码都不是其它字符的编码的前缀,例如:设有abcd需要编码表示(其中,a=0、b=10、c=110、d=11,则表示110的前缀可以是c或者da,不唯一)。 利用赫夫曼树进行信息压缩 例如我要发送语句“you see see you one day day” 一共是27个字符,一个字节八位那就是216位。但如果构造霍夫曼树得到前缀编码则可将数据压缩到 11个字节。 下面是百度百科给出的信息压缩的例子: ABFACGCAHGBBAACECDFGFAAEABBB 1.统计:A

哈夫曼树(最优二叉树)、哈夫曼编码

冷暖自知 提交于 2020-01-25 15:58:49
在此祝大家新年快乐,新的一年守住头发,不断进步! 哈夫曼树 一、哈夫曼树基本概念 二、哈夫曼树的构造算法 三、哈夫曼构造算法的实现 四、哈夫曼编码 五、哈夫曼编码的算法实现 一、哈夫曼树基本概念 (1) 路径 :从树中的一个结点到另一个结点之间的分支构成这两个结点之间的路径 (2) 路径长度 :路径上的分支数目称作路径长度。 (3) 树的路径长度 :从树根到每一结点的路径长度之和。 (4) 权 :将树中结点赋给一个有着某种含义的数值,则这个数值称为该 结点的权 。 (5) 结点的带权路径长度 :从 根结点 到该结点之间的 路径长度 与该结点的 权 的 乘机 (6) 树的带权路径长度 :树中所有 叶子结点 的 带权路径长度之和。 看以下几个例子: 我们可以总结出: 哈夫曼树:最优二叉树(带权路径长度(WPL)最短的二叉树) ,带权路径长度最短是在“度相同”的树中比较而得的结果,因此有最优二叉树、最优三叉树之称。 满二叉树不一定是哈夫曼树 哈夫曼树中权越大的叶子离根越近 具有相同带权结点的哈夫曼树不唯一 根据 权值越大的结点离根结点越近 这个特点,哈夫曼最早给出了一个构造哈夫曼树的方法,称为 哈夫曼算法 二、哈夫曼树的构造算法 典型的贪心算法:构造哈夫曼树时首先选择权值小的叶子结点。 哈夫曼算法(构造哈夫曼树的方法) (1)根据n个给定的权值{w1,w2,w3…,wn

最优二叉树

瘦欲@ 提交于 2019-12-29 16:54:54
叶子结点的权值 :对叶子结点赋予的一个有意义的数值量。 二叉树的带权路径长度 :设二叉树具有n个带权值的叶子结点,从根结点到各个叶子结点的路径长度与相应叶子结点权值的乘积之和。 记为: 哈夫曼树 :给定一组具有确定权值的叶子结点,带权路径长度最小的二叉树。 哈夫曼树的特点 : 权值越大的叶子结点越靠近根结点,而权值越小的叶子结点越远离根结点。 只有度为0(叶子结点)和度为2(分支结点)的结点,不存在度为1的结点. 哈夫曼算法基本思想: ⑴ 初始化:由给定的n个权值{w1,w2,…,wn}构造n棵只有一个根结点的二叉树,从而得到一个二叉树集合F={T1,T2,…,Tn}; ⑵ 选取与合并:在F中选取根结点的权值最小的两棵二叉树分别作为左、右子树构造一棵新的二叉树,这棵新二叉树的根结点的权值为其左、右子树根结点的权值之和; ⑶ 删除与加入:在F中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入到F中; ⑷ 重复⑵、⑶两步,当集合F中只剩下一棵二叉树时,这棵二叉树便是哈夫曼树。 哈夫曼树的存储结构 设置一个数组huffTree[2n-1]保存哈夫曼树中各点的信息,数组元素的结点结构 。 数组huffTree初始化,所有元素结点的双亲、左 右孩子都置为-1; 数组huffTree的前n个元素的权值置给定值w[n]; 进行n-1次合并 3.1 在二叉树集合中选取两个权值最小的根结点,

哈夫曼树的c++数据结构实现

大兔子大兔子 提交于 2019-12-23 21:36:02
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 哈夫曼树在理论上的构造方法很简单,不赘述,现介绍哈夫曼树的c++数据结构实现 大体来说,是一个由结构体组成的数组,每个结构体都是一个哈夫曼树的节点,数组的所有节点表示哈夫曼树,从实质上来说还是存在于一串连续的内存地址中。 1, 每个哈夫曼节点,可以用结构体表示,有权重,父子节点。父子节点的值是用节点在数组中的位置表示的。 struct element { int weight; int lchild, rchild, parent; }; 2,哈夫曼树的构造有一个规律,将n个节点构造一个哈夫曼树,需要且仅需要n-1次合并,每次合并会产生一个新节点,所以最终的哈夫曼数的数组长度为2*n-1;在初始化数组长度的时候,这一点需要注意 element *hufftree = new element[2 * n - 1]; 3,所需要的子函数有三个: 构造哈夫曼树的主函数 void createHaffumanTree(element haffTree[], int w[], int n) a——将所有节点父节点置为-1,在之后的算法中,父节点是不是-1是判断节点是否为树根的标志:是树根的节能才能参与合并。b——调用选择算法选择权重最小的两个节点,将他们合并成新的节点,并将父子,权重做合适调整

利用c++实现哈希慢算法

丶灬走出姿态 提交于 2019-12-20 04:33:19
我想每个计算机专业的学生或多或少都接触过哈夫曼编码,数据结构中的老问题了。大体就是给出一些字符,和这些字符的出现频率,让你为这些字符设计一个二进制编码,要求频率最高的字符的编码最短。解决的方法是构造一棵哈夫曼树(二叉树),其基本思路是,每次从这些字符中挑出两个频率最低的,然后构造一个新的结点,使新结点的左右孩子指针分别指向那两个节点。我想这个大家都很清楚了,我就不多说了。主要讲下这次我用C++实现时遇到的问题。首先,我定义了一个哈夫曼树结点: class hNode {  public:   friend bool operator > (hNode n1,hNode n2); //定义了大于符号,供优先队列排列使用   hNode(string d="",int i=0,hNode* l = NULL,hNode* r =NULL):left(l),right(r),data(d),value(i){}   hNode* left;   hNode* right;   string data; //储存的字符串   int value; //字符串出现的次数 }; bool operator >(hNode n1,hNode n2) {  return n1.value > n2.value; } 仅仅只是存放数据的对象,所以只有一个构造函数,并且所有的data