哈夫曼编码

哈夫曼编码问题

匿名 (未验证) 提交于 2019-12-03 00:18:01
问题描述: 给定一个文本中n个字符的出现频率。设计n个字符的哈夫曼编码。 输入 一个整数n,n<100,下面n行分别为n个字符及其出现频率 输出 所有字符的频率与其编码长度的乘积之和 示例测试集: - 第1组 输入: 5 A 35 B 10 C 20 D 20 _ 15 输出: 225 - 第2组 输入: 3 x 20 Y 50 Z 5 输出: 100 整体思路: 用自定义类node实现存储 class node { public: string word; int weight; int lchild; int rchild; int parent; public: node(string a, int b) { word = a; weight = b; lchild = -1; rchild = -1; parent = -1; } node() {} }; 将之后新建结点与当前结点都存入vector容器内 在 select()函数中实现每次挑出最小的两个数(min),并实现连接(connect) 特别需要注意的是 哈夫曼编码树 最后的结点数=数据结点*2-1 注意点: int类型最大值 MAX 0x7fffffff vector 自定义类 必须实现构造函数 printf中实现递归错误写法 将a值改变,这样无法实现遍历 void printf(int a) { cout <<

范式哈夫曼编码的快速解码技术

匿名 (未验证) 提交于 2019-12-03 00:02:01
转载自: http://blog.csdn.net/goncely/article/details/619725 1 引言 对前缀编码进行解码时,最重要的问题是如何快速的确定码字的长度。范式哈夫曼编码具有数字序列属性,因而能通过如下算法确定码字的长度: int len = 1; int code = bs.ReadBit(); while(code >= first[len]) { code <<= 1; code |= (bs.ReadBit()); // append next input bit to code len++; } len--; 另一方面,上述算法逐位进行操作,因而效率不高。快速解码算法的开发便是针对上述两个速度瓶颈而进行的。 1 一个小的改进[1] 首先看一个定理: 对于任意的两个规范哈夫曼码字w1, w2, 其码长分别为l1, l2.如果l1<l2, 那么 I(w1 1^(lmax-l1)) < I(w2 0^(lmax-l2)). 其中lmax为码字的最大长度,1^(lmax-l1)表示lmax-l1个1, w1 1^(lmax-l1)表示w1的二进制序列后面跟lmax-l1个1.w2 0^(lmax-l2)类似. I(w1 1^(lmax-l1))表示二进制序列w1 1^(lmax-l1)的整数值(无符号)。 证明:定义minword[i

范式哈夫曼编码(Canonical Huffman Code)

匿名 (未验证) 提交于 2019-12-03 00:02:01
转载自: http://blog.csdn.net/goncely/article/details/616589 1 概念介绍 哈夫曼编码是一种最优的前缀编码技术,然而其存在的不足却制约了它的直接应用。首先,其解码时间为O(lavg), 其中lavg为码字的平均长度;其次,更为最重要的是,解码器需要知道哈夫曼编码树的结构,因而编码器必须为解码器保存或传输哈夫曼编码树。对于小量数据的压缩而言,这是很大的开销。因而,应用哈夫曼编码的关键是如何降低哈夫曼编码树的存储空间。Faller[1973]提出的自适应哈夫曼编码技术使哈夫曼编码树的存储空间降为零,即在使用某种约定的情况下,解码器能动态地重构出和编码器同步的哈夫曼编码树,而不需要任何附加数据。这样做的代价便是时间开销的增大。另一种技术是编码器和解码器使用事先约定的编码树,这种方法只能针对特定数据使用,不具备通用性。另外一种,也是最为常用的方法,便是范式哈夫曼编码。现在流行的很多压缩方法都使用了范式哈夫曼编码技术,如GZIB、ZLIB、PNG、JPEG、MPEG等。 范式哈夫曼编码最早由Schwartz[1964]提出,它是哈夫曼编码的一个子集。其中心思想是:使用某些强制的约定,仅通过很少的数据便能重构出哈夫曼编码树的结构。其中一种很重要的约定是数字序列属性(numerical sequence property)

杭电OJ 1053(C )

倖福魔咒の 提交于 2019-12-02 09:13:14
本题实现哈夫曼编码,使用优先队列即可。 #include <iostream> #include <string> #include <queue> #include <functional> #include <iomanip> using namespace std; int num[30]; //各字符出现的次数 int sum; //哈夫曼编码总长度 priority_queue <int, vector<int>, greater<int>> q; //升序优先队列 void encode(); //实现哈夫曼编码 int main() { string str; while (cin >> str) { if (str == "END") break; sum = 0; memset(num, 0, sizeof(num)); while (!q.empty()) //将之前计算中队列剩余元素清空(只有一个元素时会剩余) q.pop(); for (int i = 0; i < str.length(); i++) { if (str[i] == '_') num[26]++; else num[str[i] - 'A']++; } for (int i = 0; i < 30; i++) { if (num[i] > 0) q.push(num[i]); /

For noip2019 初赛(csp)

流过昼夜 提交于 2019-12-01 17:17:15
1962年CCF成立 1984年NOI首次举办 1995年noip首次举办 2019年CSP非专业组首次举办 前序、中序、后序遍历:先访问当前节点,或在中间访问,或在最后访问 前序遍历即为DFS序 哈夫曼编码:哈夫曼编码,主要目的是根据使用频率来最大化节省字符(编码)的存储空间。 https://blog.csdn.net/qq_36653505/article/details/81701181 例题: [TG2011] 现有一段文言文,要通过二进制哈夫曼编码进行压缩。简单起见,假设这段文言文只由4个汉字“之”、“乎”、“者”、“也”组成,它们出现的次数分别为700、600、300、400。那么,“也”字的编码长度可能是( )。 两种组成方式:300+400,得到700,然后和600拼接,得到1300,然后和原来的700拼接,长度为3 如果600和700先拼接,那么长度将仅为2 Catalan Numbers 设h(n)为catalan数的第n+1项,令h(0)=1,h(1)=1,catalan数满足递推式:h(n)= h(0) h(n-1)+h(1) h(n-2) + ... + h(n-1)*h(0) (n>=2) 则有h(n)=C(2n,n)/(n+1) https://blog.csdn.net/wookaikaiko/article/details/81105031

哈夫曼编码(前缀编码)理解

蹲街弑〆低调 提交于 2019-11-30 00:32:23
5,6,2,9,7 哈夫曼编码 比如文字内容”ABCDEF”,通过二进制数据表示 传输数据为:“000001010011100101”按照3位一分来译码即可,但可以想象假如文字多了,数据量也是相当的大。 所以需要 前缀编码(就是最短数据进行传输) 来进行编码(哈夫曼思想) 前缀编码:设计长短不等的编码,必须是任一字符的编码都不是另一个字符编码的前缀,这种编码称为前缀编码 因为每个字母的出现频率是不同的,我们假设给每个字母分配权值:A:27,B:8,C:15,D:15,E:30,F:5,首先按照它们的权值进行构造哈夫曼树 将所有权值左分支改为0,右分支改为1. 就是前缀。 来源: CSDN 作者: mengxuepingwxhn 链接: https://blog.csdn.net/qq_38998213/article/details/103246413

哈夫曼树及编码讲解及例题

痞子三分冷 提交于 2019-11-29 03:26:21
哈弗曼树及编码 哈弗曼树算法 第一步: 初始化n个单节点的树,并为它们表上字母中的字符。把每个字符的概率记在树的根中,用来指出树的权重(更一般地说,树的权重等于树中所有叶子的概率之和)。 第二部: 重复下面的操作,直到只剩下一颗单独的树。找到两颗权重最小的树(对于权重相同的树,可任意选择其一)。把它们作为新树中的左右子树,并把其权重之和作为新的权重记录在新树的根中。 上面的算法构造的树称为 哈弗曼树 ,它按照刚才的描述定义了一套 哈夫曼编码 。 例: 字符 A B C D _ 出现概率 0.35 0.1 0.2 0.2 0.15 代码字 11 100 00 01 101 因此,DAD被编码为011101,而10011011011101编码以后就是BAD_AD。 构造哈弗曼编码树的一个例子图: 在这套编码中,每个字符的平均位长是 2 ∗ 0.35 + 3 ∗ 0.1 + 2 ∗ 0.2 + 2 ∗ 0.2 + 3 ∗ 0.15 = 2.25 2*0.35+3*0.1+2*0.2+2*0.2+3*0.15=2.25 2 ∗ 0 . 3 5 + 3 ∗ 0 . 1 + 2 ∗ 0 . 2 + 2 ∗ 0 . 2 + 3 ∗ 0 . 1 5 = 2 . 2 5 可见,我们可以指望一个文本的哈夫曼编码要比其定长编码少占用25%的存储空间。 哈夫曼编码是一种最重要的文件压缩方法。 例图:

哈夫曼编解码压缩解压文件—C++实现

泄露秘密 提交于 2019-11-28 12:53:12
前言 哈夫曼编码是一种贪心算法和二叉树结合的字符编码方式,具有广泛的应用背景,最直观的是文件压缩。本文主要讲述如何用哈夫曼编解码实现文件的压缩和解压,并给出代码实现。 哈夫曼编码的概念 哈夫曼树又称作最优树,是一种带权路径长度最短的树,而通过哈夫曼树构造出的编码方式称作哈夫曼编码。 也就是说哈夫曼编码是一个通过哈夫曼树进行的一种编码,一般情况下,以字符 “0” 与 “1” 表示。编码的实现过程很简单,只要实现哈夫曼树,通过遍历哈夫曼树,这里我们从根节点开始向下遍历,如果下个节点是左孩子,则在字符串后面追加 “0”,如果为其右孩子,则在字符串后追加 “1”。结束条件为当前节点为叶子节点,得到的字符串就是叶子节点对应的字符的编码。 哈夫曼树实现 根据贪心算法的思想实现,把字符出现频率较多的字符用稍微短一点的编码,而出现频率较少的字符用稍微长一点的编码。哈夫曼树就是按照这种思想实现,下面将举例分析创建哈夫曼树的具体过程。下面表格的每一行分别对应字符及出现频率,根据这些信息就能创建一棵哈夫曼树。 字符 出现频率 编码 总二进制位数 a 500 1 500 b 250 01 500 c 120 001 360 d 60 0001 240 e 30 00001 150 f 20 00000 100 如下图,将每个字符看作一个节点,将带有频率的字符全部放到优先队列中

【NOI2015】荷马史诗

与世无争的帅哥 提交于 2019-11-26 14:12:43
   题目链接 https://www.luogu.org/problem/P2168    题目大意 是给定 n 个单词 的出现次数 wi ,求用 k 进制的前缀码转换后得到的最小总长度,以及在保证总长度最小时的最长串 si 的长度最短。   这题现在来看算是NOI里很简单的了(我竟然凹出来了w),但是据说当时这题可是难倒一大片。首先是因为这题题干太长不怎么容易看懂,另外可能是因为当时哈弗曼树还没有那么常见,几乎没人想到有哈弗曼树这么一个东西。   好,来看题。题目很明确,目标是要使编码之后的总长度最小,那么现在就要想着,怎样把出现次数多的编码长度尽可能的缩小。但是题目里有个限制:任意一个k进制编码都不是其它编码的前缀。这样一来,题目的做法就指向了哈弗曼树。    哈弗曼树与哈夫曼编码    这里简单重复一下 ——(证明过程引用自耿国华主编的《数据结构——C语言描述》)   哈夫曼树特性:从根结点到所有叶子结点的带权路径长度最短(就是权大的放靠近树根的地方)   做法:挑选序列里最小的2个点合并作为子节点,根节点的权值为他们的和,把根节点加入原序列,重复上述操作。   哈夫曼编码特性:1.它是前缀码。前缀码就是题目里给的那种,任何一个编码都不是其它编码的前 t 项。 证明:哈夫曼编码是根到叶子路径上的边的编码序列,也就是等价边序列,而由树的特点可知