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. webstrom使用

    主题 主题下载:http://color-themes.com/?view=index&page=1&order=popular&search=&layout=HTML ...

  2. Html + JS : 点击对应的按钮,进行选择是隐藏还是显示(用户回复功能)

    例如: 当我点击按钮1时,点击第一下进行显示This is comment 01,点击第二下隐藏This is comment 01 当我点击按钮2时,点击第一下进行显示This is comment ...

  3. Arduino入门教程--课前准备--Arduino驱动安装及1.0 IDE菜单介绍

    编译器版本:Arduino 1.0实验器件:ocrobot mango控制板(Arduino兼容)一块 Arduino控制板到手后,首先需要在电脑上把驱动装上,这样才可以进行各种实验. 第一步需要把A ...

  4. MYSQL忘记超级用户密码修改

    #service mysql stop #mysqld_safe --skip-grant-tables 另外开个SSH连接或终端 [root@localhost ~]# mysql mysql> ...

  5. 基于ASP.NET WPF技术及MVP模式实战太平人寿客户管理项目开发(Repository模式)

    亲爱的网友,我这里有套课程想和大家分享,假设对这个课程有兴趣的.能够加我的QQ2059055336和我联系.  课程背景 本课程是教授使用WPF.ADO.NET.MVVM技术来实现太平人寿保险有限公司 ...

  6. 5、Oracle备份(oracle备份脚本配置)

    1.1 Oracle数据库备份 1.1.1 链接Oracle介质管理库 请在数据库节点上操作. [oracle@db01/usr/openv/netbackup/bin]$ ./oracle_link ...

  7. 解决SurfaceView调用setZOrderOnTop(true)遮挡其他控件的问题

    SurfaceView遮挡其他控件的项目背景: 最近在做播放器项目,由于底层实现是用Surface和OpenGL切换渲染,所以在布局里面同时使用了GLSurfaceView和SurfaceView,同 ...

  8. node.js 练习2 (调用函数)

    1. 调用本地 函数 (1)  创建 n2-1.js ,并输入代码 (2) 运行localhhost:8000 (3)在浏览器中 查看 (4)在cmd中查看 2.调用外部 函数 (1) 创建n2-2. ...

  9. 第31章 TIM—基本定时器—零死角玩转STM32-F429系列

    第31章     TIM—基本定时器 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fire ...

  10. 网际协议 IP

    网际协议 网际协议(internet  protocol),简称IP; 概念:TCP/IP网络体系结构中网际层的协议.用以提供无连接的数据服务. 1.IP地址的概念及组成 概念:IP地址就是用来唯一标 ...