huffman编码——原理与实现
哈夫曼算法原理
Wikipedia上面说的非常清楚了,这里我就不再赘述,直接贴过来了。
1952年, David A. Huffman提出了一个不同的算法,这个算法能够为不论什么的可能性提供出一个理想的树。香农-范诺编码(Shanno-Fano)是从树的根节点到叶子节点所进行的的编码,哈夫曼编码算法却是从相反的方向,暨从叶子节点到根节点的方向编码的。
- 为每一个符号建立一个叶子节点,并加上其对应的发生频率
- 当有一个以上的节点存在时,进行下列循环:
- 把这些节点作为带权值的二叉树的根节点,左右子树为空
- 选择两棵根结点权值最小的树作为左右子树构造一棵新的二叉树,且至新的二叉树的根结点的权值为其左右子树上根结点的权值之和。
- 把权值最小的两个根节点移除
- 将新的二叉树添�队列中.
- 最后剩下的节点暨为根节点,此时二叉树已经完毕。
演示样例

Huffman Algorithm

-
符号 A B C D E 计数 15 7 6 6 5 概率 0.38461538 0.17948718 0.15384615 0.15384615 0.12820513
在这样的情况下,D,E的最低频率和分配分别为0和1,分组结合概率的0.28205128。如今最低的一双是B和C,所以他们就分配0和1组合结合概率的0.33333333在一起。这使得BC和DE所以0和1的前面加上他们的代码和它们结合的概率最低。然后离开仅仅是一个和BCDE,当中有前缀分别为0和1,然后结合。这使我们与一个单一的节点,我们的算法是完整的。
可得A代码的代码长度是1比特,其余字符是3比特。
-
字符 A B C D E 代码 0 100 101 110 111

Pseudo-code
1: begin
2: count frequencies of single characters (source units)
3: output(frequencies using Fibonacci Codes of degree 2)
4: sort them to non-decreasing sequence
5: create a leaf node (character, frequency c, left son = NULL, right son = NULL)
6: of the tree for each character and put nodes into queue F
7: while (|F|>=2) do
8: begin
9: pop the first two nodes (u1, u2) with the lowest
10: frequencies from sorted queue
11: create a node evaluated with sum of the chosen units,
12: successors are chosen units (eps, c(u1)+c(u2), u1, u2)
13: insert new node into queue
14: end
15: node evaluate with way from root to leaf node (left son 1, right son 0)
16: create output from coded intput characters
17: end
哈夫曼算法实现
/************************************************************************/
/* File Name: Huffman.cpp
* @Function: Lossless Compression
@Author: Sophia Zhang
@Create Time: 2012-9-26 10:40
@Last Modify: 2012-9-26 11:10
*/
/************************************************************************/ #include"iostream"
#include "queue"
#include "map"
#include "string"
#include "iterator"
#include "vector"
#include "algorithm"
using namespace std; #define NChar 8 //suppose use at most 8 bits to describe all symbols
#define Nsymbols 1<<NChar //can describe 256 symbols totally (include a-z, A-Z)
typedef vector<bool> Huff_code;//8 bit code of one char
map<char,Huff_code> Huff_Dic; //huffman coding dictionary class HTree
{
public :
HTree* left;
HTree* right;
char ch;
int weight; HTree(){left = right = NULL; weight=0;}
HTree(HTree* l,HTree* r,int w,char c){left = l; right = r; weight=w; ch=c;}
~HTree(){delete left; delete right;}
int Getweight(){return weight?weight:left->weight+right->weight;}
bool Isleaf(){return !left && !right; }
bool operator < (const HTree tr) const
{
return tr.weight < weight;
}
}; HTree* BuildTree(int *frequency)
{
priority_queue<HTree*> QTree; //1st level add characters
for (int i=0;i<Nsymbols;i++)
{
if(frequency[i])
QTree.push(new HTree(NULL,NULL,frequency[i],(char)i));
} //build
while (QTree.size()>1)
{
HTree* lc = QTree.top();
QTree.pop();
HTree* rc = QTree.top();
QTree.pop(); HTree* parent = new HTree(lc,rc,parent->Getweight(),(char)256);
QTree.push(parent);
}
//return tree root
return QTree.top();
} void Huffman_Coding(HTree* root, Huff_code& curcode)
{
if(root->Isleaf())
{
Huff_Dic[root->ch] = curcode;
return;
}
Huff_code& lcode = curcode;
Huff_code& rcode = curcode;
lcode.push_back(false);
rcode.push_back(true); Huffman_Coding(root->left,lcode);
Huffman_Coding(root->right,rcode);
} int main()
{
int freq[Nsymbols] = {0};
char *str = "this is the string need to be compressed"; //statistic character frequency
while (*str!='\0')
freq[*str++]++; //build tree
HTree* r = BuildTree(freq);
Huff_code nullcode;
nullcode.clear();
Huffman_Coding(r,nullcode); for(map<char,Huff_code>::iterator it = Huff_Dic.begin(); it != Huff_Dic.end(); it++)
{
cout<<(*it).first<<'\t';
Huff_code vec_code = (*it).second;
for (vector<bool>::iterator vit = vec_code.begin(); vit!=vec_code.end();vit++)
{
cout<<(*vit)<<endl;
}
}
}
那我们将friend bool operator >(Node node1,Node node2)改动为friend bool operator >(Node* node1,Node* node2),也就是传递的是Node的指针行不行呢?
答案是不能够,由于依据c++primer中重载操作符中讲的“程序猿仅仅能为类类型或枚举类型的操作数定义重载操作符,在把操作符声明为类的成员时,至少有一个类或枚举类型的參数依照值或者引用的方式传递”,也就是说friend
bool operator >(Node* node1,Node* node2)形參中都是指针类型的是不能够的。我们仅仅能再建一个类,用当中的重载()操作符作为优先队列的比較函数。
就得到了以下正确的代码:
/************************************************************************/
/* File Name: Huffman.cpp
* @Function: Lossless Compression
@Author: Sophia Zhang
@Create Time: 2012-9-26 10:40
@Last Modify: 2012-9-26 12:10
*/
/************************************************************************/ #include"iostream"
#include "queue"
#include "map"
#include "string"
#include "iterator"
#include "vector"
#include "algorithm"
using namespace std; #define NChar 8 //suppose use 8 bits to describe all symbols
#define Nsymbols 1<<NChar //can describe 256 symbols totally (include a-z, A-Z)
typedef vector<bool> Huff_code;//8 bit code of one char
map<char,Huff_code> Huff_Dic; //huffman coding dictionary /************************************************************************/
/* Tree Class elements:
*2 child trees
*character and frequency of current node
*/
/************************************************************************/
class HTree
{
public :
HTree* left;
HTree* right;
char ch;
int weight; HTree(){left = right = NULL; weight=0;ch ='\0';}
HTree(HTree* l,HTree* r,int w,char c){left = l; right = r; weight=w; ch=c;}
~HTree(){delete left; delete right;}
bool Isleaf(){return !left && !right; }
}; /************************************************************************/
/* prepare for pointer sorting*/
/*because we cannot use overloading in class HTree directly*/
/************************************************************************/
class Compare_tree
{
public:
bool operator () (HTree* t1, HTree* t2)
{
return t1->weight> t2->weight;
}
}; /************************************************************************/
/* use priority queue to build huffman tree*/
/************************************************************************/
HTree* BuildTree(int *frequency)
{
priority_queue<HTree*,vector<HTree*>,Compare_tree> QTree; //1st level add characters
for (int i=0;i<Nsymbols;i++)
{
if(frequency[i])
QTree.push(new HTree(NULL,NULL,frequency[i],(char)i));
} //build
while (QTree.size()>1)
{
HTree* lc = QTree.top();
QTree.pop();
HTree* rc = QTree.top();
QTree.pop(); HTree* parent = new HTree(lc,rc,lc->weight+rc->weight,(char)256);
QTree.push(parent);
}
//return tree root
return QTree.top();
} /************************************************************************/
/* Give Huffman Coding to the Huffman Tree*/
/************************************************************************/
void Huffman_Coding(HTree* root, Huff_code& curcode)
{
if(root->Isleaf())
{
Huff_Dic[root->ch] = curcode;
return;
}
Huff_code lcode = curcode;
Huff_code rcode = curcode;
lcode.push_back(false);
rcode.push_back(true); Huffman_Coding(root->left,lcode);
Huffman_Coding(root->right,rcode);
} int main()
{
int freq[Nsymbols] = {0};
char *str = "this is the string need to be compressed"; //statistic character frequency
while (*str!='\0')
freq[*str++]++; //build tree
HTree* r = BuildTree(freq);
Huff_code nullcode;
nullcode.clear();
Huffman_Coding(r,nullcode); for(map<char,Huff_code>::iterator it = Huff_Dic.begin(); it != Huff_Dic.end(); it++)
{
cout<<(*it).first<<'\t';
std::copy(it->second.begin(),it->second.end(),std::ostream_iterator<bool>(cout));
cout<<endl;
}
}

huffman编码——原理与实现的更多相关文章
- [老文章搬家] 关于 Huffman 编码
按:去年接手一个项目,涉及到一个一个叫做Mxpeg的非主流视频编码格式,编解码器是厂商以源代码形式提供的,但是可能代码写的不算健壮,以至于我们tcp直连设备很正常,但是经过一个UDP数据分发服务器之后 ...
- 哈夫曼(Huffman)编码
哈夫曼编码(Huffman Coding)是一种非常经典的编码方式,属于可变字长编码(VLC)的一种,通过构造带权路径长度最小的最优二叉树以达到数据压缩的目的.哈弗曼编码实现起来也非常简单,在实际的笔 ...
- Huffman编码实现文件的压缩与解压缩。
以前没事的时候写的,c++写的,原理很简单,代码如下: #include <cstdio> #include <cstdlib> #include <iostream&g ...
- Huffman编码实现压缩解压缩
这是我们的课程中布置的作业.找一些资料将作业完毕,顺便将其写到博客,以后看起来也方便. 原理介绍 什么是Huffman压缩 Huffman( 哈夫曼 ) 算法在上世纪五十年代初提出来了,它是一种无损压 ...
- 基于二叉树和双向链表实现限制长度的最优Huffman编码
该代码採用二叉树结合双向链表实现了限制长度的最优Huffman编码,本文代码中的权重所有採用整数值表示.http://pan.baidu.com/s/1mgHn8lq 算法原理详见:A fast al ...
- Huffman编码实验
一. 实验目的 熟练掌握哈夫曼树的建立和哈夫曼编码的算法实现. 二. 实验内容 根据哈夫曼编码的原理,编写一个程序,在用户输入结点权值的基础上求赫夫曼编码,并能把给定的编码进行译码. 三. 实验要求 ...
- Huffman编码
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <cstri ...
- 【数据压缩】Huffman编码
1. 压缩编码概述 数据压缩在日常生活极为常见,平常所用到jpg.mp3均采用数据压缩(采用Huffman编码)以减少占用空间.编码\(C\)是指从字符空间\(A\)到码字表\(X\)的映射.数据压缩 ...
- 优先队列求解Huffman编码 c++
优先队列小析 优先队列的模板: template <class T, class Container = vector<T>,class Compare = less< ...
随机推荐
- 推送:腾迅信鸽 VS Bmob
最近几天了解市场上主流的推送SDK. 腾迅信鸽 所需SDK,去官网自行下载.去下载 完整的清单文件如下: <?xml version="1.0" encoding=" ...
- CRT detected that the application wrote to memory after end of heap buffer.
很多人的解释都不一样, 我碰到的问题是,开辟的内存空间小于操作的内存空间.也就是说,我free的内存越界了. 这是我开辟链表结构体内存的代码: PNODE Create() { int len; / ...
- Python报错:SyntaxError: Non-ASCII character '\xe5' in file
运行Python脚本总是报一下的错误: SyntaxError: Non-ASCII character '\xe5' in file 原因:Python默认是以ASCII作为编码方式的,如果在自己的 ...
- c/c++内存机制(一)(转)
转自:http://www.cnblogs.com/ComputerG/archive/2012/02/01/2334898.html 一:C语言中的内存机制 在C语言中,内存主要分为如下5个存储区: ...
- jquery mobile navbar
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...
- mybatis 学习笔记(4) —— 批量新增数据
1.业务是从前台传入List<T> ,在controller层接受参数,并进行批量新增操作. 2.需要处理的细节 a) mybatis可以支持批量新增,注意数据表需要将主键设置成自增列. ...
- 原创 HTML5:JS操作SVG实践体会
在工业信息化系统里,常常需要动态呈现系统的数据在一张示意图里,用于展现系统状态,分析结果等.这样用JavaScript操作svg 元素就有现实意义.本人近期做了一些实践,现分享一下. 需求: 你下面这 ...
- ASP.NET 无权访问所请求的资源。请考虑对 ASP.NET 请求标识授予访问此资源的权限。
如题,在编译程序时,没有问题,但是通过iis设置的网站进入时,报如上错误.asp.net有个运行账户,一般情况下iis5为aspnet,iis6为network service,在iis里面确认一下是 ...
- d038: 星罗密布
内容: 输出图形 *****$***$$$*$$$$$ 规律是...自己发现吧. 要求输入3,输出上面三行的图形 输入说明: 行数小于40 输出说明: 输入样例: 3 输出样例 : ***** ...
- MVC中的区域
authour: chenboyi updatetime: 2015-05-03 08:26:30 friendly link: 目录: 1,思维导图 2,AreaRegistration类的Re ...