2014.07.06 16:47

简介:

  给定一段有固定符号集合S构成的文本T,集合S中总共有n种符号。如果对于每种符号,使用一种不同的由‘0’和‘1’构成的位字符串来代替,比如:

    ‘a’->‘01’

    ‘c’->'101'

    'd'->‘11’

    ...

  例如,文本“acd”经过这种编码就变成了“0110111”。

  这样,就可以把文本T中的符号全部替换为‘0’‘1’构成的二进制串,这样就能以二进制文件的形式保存信息了。并且,一个ASCII字符默认占用一个字节,也就是8位。但使用这种不定长的编码方式一个字符占用的位数可能小于8位,于是可能达到压缩数据的效果。Huffman编码的规则,就是通过选定合适的编码,使得这段文本经过编码转换后的二进制串的长度最短。

图示:

  用算法描述Huffman编码的过程还是比较简单的:

  1. 定义键值对<字符, 出现频率>,比如<a, 12>表示a字符出现了12次。

  

  2. 每次选出出现频率最低的两个字符,组合成一个字符(字符当然不能组合,但频率是可以相加的),重新放入候选集中。

  

  3. 这个组合的过程,其实就是构建二叉树的过程

  

  新结点的频率等于两个子节点的频率之和,而新节点上对应的字符没有实际意义,所以我们姑且标记为‘?’。

  每经过一轮这样的操作,我们取出两个结点,放回一个结点,所以要经过n-1轮才能得到一棵完整的树,比如这样:

  

  上图中给出了这棵树对应的字符编码方式,其实每个字符的编码对应于从根结点到叶结点的路径,‘0’向左,‘1’向右。

  由于组合两个结点时,左右次序可以调换,因此同一套文本与字符可以构建出2^(n-1)种的Huffman树。任何一种的效果都是相同的,目的只有一个:压缩数据。

  如何每次选出最小的两个呢?最小堆。

  问题是:为什么每次选出最小的,结果就是最好的呢?贪婪。

实现:

 // A simple illustration for
#include <iostream>
#include <queue>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std; // The character statistics type
typedef unordered_map<char, int> StatType;
// The character encoding type
typedef unordered_map<char, string> EncodeType; struct TreeNode {
char ch;
int weight;
TreeNode *left;
TreeNode *right; TreeNode(char _ch, int _weight): ch(_ch), weight(_weight),
left(nullptr), right(nullptr) {}
}; struct GreaterFunctor {
bool operator () (const TreeNode *x, const TreeNode *y) {
return x->weight > y->weight;
}
}; void deleteTree(TreeNode *&root)
{
if (root == nullptr) {
return;
} else {
deleteTree(root->left);
deleteTree(root->right);
delete root;
root = nullptr;
}
} void calculateEncoding(const TreeNode *root, EncodeType &encoding, string &path)
{
if (root == nullptr) {
return;
} if (root->ch != '\0') {
encoding[root->ch] = path;
return;
} path.push_back('');
calculateEncoding(root->left, encoding, path);
path.pop_back(); path.push_back('');
calculateEncoding(root->right, encoding, path);
path.pop_back();
} void huffmanEncoding(const StatType &statistics, EncodeType &encoding)
{
priority_queue<TreeNode *, vector<TreeNode *>, GreaterFunctor> pq; int n; n = ;
for (StatType::const_iterator sta_it = statistics.begin();
sta_it != statistics.end(); ++sta_it) {
pq.push(new TreeNode(sta_it->first, sta_it->second));
++n;
} TreeNode *p1, *p2, *p3;
int i;
for (i = ; i < n - ; ++i) {
p1 = pq.top();
pq.pop();
p2 = pq.top();
pq.pop(); p3 = new TreeNode('\0', p1->weight + p2->weight);
p3->left = p1;
p3->right = p2;
pq.push(p3);
} TreeNode *root = pq.top();
pq.pop(); string code = "";
calculateEncoding(root, encoding, code);
deleteTree(root);
} int main()
{
int i, n;
string s;
int weight;
StatType statistics;
EncodeType encoding; while (cin >> n && n > ) {
for (i = ; i < n; ++i) {
cin >> s >> weight;
statistics[s[]] = weight;
}
huffmanEncoding(statistics, encoding); for (EncodeType::const_iterator enc_it = encoding.begin();
enc_it != encoding.end(); ++enc_it) {
cout << enc_it->first << ':' << enc_it->second << endl;
}
cout << endl; statistics.clear();
encoding.clear();
} return ;
}

《数据结构与算法分析:C语言描述》复习——第十章“算法设计技巧”——Huffman编码的更多相关文章

  1. 数据结构与算法分析——C语言描述 第三章的单链表

    数据结构与算法分析--C语言描述 第三章的单链表 很基础的东西.走一遍流程.有人说学编程最简单最笨的方法就是把书上的代码敲一遍.这个我是头文件是照抄的..c源文件自己实现. list.h typede ...

  2. 最小正子序列(序列之和最小,同时满足和值要最小)(数据结构与算法分析——C语言描述第二章习题2.12第二问)

    #include "stdio.h" #include "stdlib.h" #define random(x) (rand()%x) void creat_a ...

  3. C语言学习书籍推荐《数据结构与算法分析:C语言描述(原书第2版)》下载

    维斯 (作者), 冯舜玺 (译者) <数据结构与算法分析:C语言描述(原书第2版)>内容简介:书中详细介绍了当前流行的论题和新的变化,讨论了算法设计技巧,并在研究算法的性能.效率以及对运行 ...

  4. 《数据结构与算法分析——C语言描述》ADT实现(NO.00) : 链表(Linked-List)

    开始学习数据结构,使用的教材是机械工业出版社的<数据结构与算法分析——C语言描述>,计划将书中的ADT用C语言实现一遍,记录于此.下面是第一个最简单的结构——链表. 链表(Linked-L ...

  5. 《数据结构与算法分析-Java语言描述》 分享下载

    书籍信息 书名:<数据结构与算法分析-Java语言描述> 原作名:Data Structures and Algorithm Analysis in Java 作者: 韦斯 (Mark A ...

  6. 读书笔记:《数据结构与算法分析Java语言描述》

    目录 第 3 章 表.栈和队列 3.2 表 ADT 3.2.1 表的简单数组实现 3.2.2 简单链表 3.3 Java Collections API 中的表 3.3.1 Collection 接口 ...

  7. 《数据结构与算法分析:C语言描述_原书第二版》CH3表、栈和队列_reading notes

    表.栈和队列是最简单和最基本的三种数据结构.基本上,每一个有意义的程序都将明晰地至少使用一种这样的数据结构,比如栈在程序中总是要间接地用到,不管你在程序中是否做了声明. 本章学习重点: 理解抽象数据类 ...

  8. 【数据结构与算法分析——C语言描述】第二章总结 算法分析

    算法 算法(algorithm)是为求解一个问题需要遵循的.被清楚地指定的简单指令的集合. 数学基础 四个定义: 1.大O表示法: 如果存在正常数 c 和 n0 使得当 N ≥ n0时,T(N) ≤ ...

  9. 【数据结构与算法分析——C语言描述】第一章总结 引论

    这一章主要复习了一些数学知识,像指数.对数.模运算.级数公式:还有2种证明方法,归纳假设法和反证法.所幸以前学过,重新拾捡起来也比较轻松. 简要地复习了递归,提出了编写递归例程的四条基本法则: 基准情 ...

随机推荐

  1. mysql : 修改数据库权限

    解决步骤 第一步,点击用户 注意!!! 编辑权限,在我们设置权限之前,我们需要先重新加载才能生效, 如果不用编辑的话,直接按重新载入编辑,这个相当于保存. 中文意思(注意看那段话) 第二步 选择要处理 ...

  2. naive bayes classifier in data mining

    https://www-users.cs.umn.edu/~kumar001/dmbook/slides/chap4_naive_bayes.pdf  -- textbook https://www. ...

  3. IOS 多线程-NSThread 和线程状态

    @interface HMViewController () - (IBAction)btnClick; @end @implementation HMViewController - (void)v ...

  4. 【[SDOI2017]新生舞会】

    题目 好题啊 我们要求的是 \[C=\frac{\sum_{i=1}^na_i}{\sum_{i=1}^nb_i}\] 使得\(C\)最大 显然 \[C\times \sum_{i=1}^nb_i=\ ...

  5. 使用 NetBackup 命令创建 Hyper-V 策略(命令创建其他策略也是如此)

    Veritas NetBackup™ for Hyper-V 管理指南 Product(s): NetBackup (8.1) 使用 NetBackup 命令创建 Hyper-V 策略 本主题介绍如何 ...

  6. redis hash类型

  7. 分类算法简介 基于R

    最近的关键字:分类算法,outlier detection, machine learning 简介: 此文将 k-means,decision tree,random forest,SVM(supp ...

  8. css隐藏元素的六类13种方法

    隐藏元素的方法 隐藏元素的方法可以总结为六类:直接隐藏.对溢出内容隐藏.对元素透明度进行调整.将元素移除当前屏幕.对元素的层级关系进行调整.对元素进行裁剪 只有对元素的透明度进行调整才可以点击,其余都 ...

  9. 正定矩阵(Positive-definite Matrix)

    原文链接 正定矩阵是自共轭矩阵的一种.正定矩阵类似复数中的正实数.定义:对于对称矩阵M,当且仅当存在任意向量x,都有 若上式大于等于零,则称M为半正定矩阵.正定矩阵记为M>0.也被称为正定二次型 ...

  10. 键盘遮挡控件(textfield/textview.......)

    采用的是通知的常规方式 // 解决键盘遮挡问题//选择didShow是因为需要键盘的高度//选择willHide是因为视图frame重置需要优先于键盘消失,否则表现得不连贯 [[NSNotificat ...