数据压缩算法之哈夫曼编码(HUFFMAN)的实现
HUFFMAN编码可以很有效的压缩数据,通常可以压缩20%到90%的空间(算法导论)。具体的压缩率取决于数据的特性(词频)。如果采取标准的语料库进行编码,一般可以得到比较满意的编码结果(对不同文件产生不同压缩率的折中方法)。
本文采取对单独一个文件进行编码的方式来演示此压缩算法的使用。
分为下面几个步骤:
1.统计词频数据
2.词频数据转换成HUFFMAN算法能够处理的类型(本文为HuffmanNode,内部有存储词频和树节点的结构)
(1)由输入的HuffmanNode[]数组创建最小优先级队列
(2)依次取出队列中的每两个节点,然后由此两个节点构造一个新的节点,然后在重新插入回队列。直到队列中只剩唯一一个节点。
此节点为编码树的根节点。
(3)依次遍历原来输入的每个HUFFMAN节点,得到每个字符的对应编码(压缩使用)。
(4)解码方式,依次输入0/1字符码到算法,算法遍历产生的编码树,如果有返回字符,则得到解码字符。
词频统计的实现:
public class FrequencyCounter
{
public IEnumerable<KeyValuePair<char, int>> MapReduce(string str)
{
//the GroupBy method is acting as the map,
//while the Select method does the job of reducing the intermediate results into the final list of results.
var wordOccurrences = str
.GroupBy(w => w)
.Select(intermediate => new
{
Key = intermediate.Key,
Value = intermediate.Sum(w => )
})
.OrderBy(kvp => kvp.Value);
IEnumerable<KeyValuePair<char, int>> kvps = from wo in wordOccurrences select new KeyValuePair<char, int>(wo.Key, wo.Value);
return kvps;
}
}
MapReduce
HUFFMAN编码类的实现:
public class Huffman
{
private List<HuffmanNode> originalNodes;
private HuffmanNode rootNode;
public Huffman(IEnumerable<KeyValuePair<char, int>> kvps)
{
//保存原始数据
var tmpOriginalNodes = from kvp in kvps select new HuffmanNode(kvp.Key, kvp.Value);
//创建最小优先队列,并输入数据
MinPriorityQueue<HuffmanNode> minQueue = new MinPriorityQueue<HuffmanNode>();
originalNodes = new List<HuffmanNode>();
foreach (var node in tmpOriginalNodes)
{
originalNodes.Add(node);
minQueue.Insert(node);
}
//建造编码树,并取得编码树的根节点
while (!minQueue.IsEmpty)
{
HuffmanNode left = minQueue.ExtractMin();
if (minQueue.IsEmpty)
{
rootNode = left;
break;
}
HuffmanNode right = minQueue.ExtractMin();
HuffmanNode newNode = new HuffmanNode(null, left.Value + right.Value, left, right);
left.Parent = newNode;
right.Parent = newNode;
minQueue.Insert(newNode);
}
}
//只接受单个char的加密
public string Encode(char sourceChar)
{
HuffmanNode hn = originalNodes.FirstOrDefault(n => n.Key == sourceChar);
if (hn == null) return null;
HuffmanNode parent = hn.Parent;
StringBuilder rtn = new StringBuilder();
while (parent != null)
{
if (Object.ReferenceEquals(parent.Left, hn))//左孩子,编码为0
{
rtn.Insert(, "", );
}
else//右孩子,编码为1
{
rtn.Insert(, "", );
}
hn = parent;
parent = parent.Parent;
}
return rtn.ToString();
}
//只接受一个字符的解码输出
public bool Decode(string string01, out char? output)
{
HuffmanNode tmpNode = rootNode;
char[] chars = string01.Trim().ToCharArray();
for (int i = ; i < chars.Count(); i++)
{
if (chars[i] == '') tmpNode = tmpNode.Left;
if (chars[i] == '') tmpNode = tmpNode.Right;
}
if (tmpNode != null && tmpNode.Left == null && tmpNode.Right==null)
{
output = tmpNode.Key;
return true;
}
else
{
output = null;
return false;
}
} class HuffmanNode : IHeapValue
{
public HuffmanNode(char? key, int value, HuffmanNode left = null, HuffmanNode right = null)
{
this.Left = left;
this.Right = right;
this.Key = key;
this.Value = value;
}
public HuffmanNode Left { get; private set; }
public HuffmanNode Right { get; private set; }
public HuffmanNode Parent { get; set; }
public char? Key { get; private set; }
public int Value { get; set; }
}
}
对文本进行编码的用法:
FrequencyCounter fc = new FrequencyCounter();
var kvps = fc.MapReduce(这里是你的文本);
hm = new Huffman(kvps);
StringBuilder sb = new StringBuilder();
string ori =这里是你的文本;
char[] chararray = ori.ToCharArray();
for (int i = ; i < chararray.Length; i++)
{
sb.Append(hm.Encode(chararray[i]));
}
对编码进行解码:
string bstr =你的编码后的文本;
StringBuilder sb = new StringBuilder();
char? outchar = null;
string tmpStr = null;
for (int i = ; i < bstr.Length; i++)
{
tmpStr = tmpStr + bstr[i];
if (hm.Decode(tmpStr, out outchar))
{
tmpStr = null;
sb.Append(outchar);
}
}
测试效果,可以看到压缩效果还是很明显的:

完毕。
作者:Andy Zeng
欢迎任何形式的转载,但请务必注明出处。
http://www.cnblogs.com/andyzeng/p/3703321.html
数据压缩算法之哈夫曼编码(HUFFMAN)的实现的更多相关文章
- 数据压缩之经典——哈夫曼编码(Huffman)
(笔记图片截图自课程Image and video processing: From Mars to Hollywood with a stop at the hospital的教学视频,使用时请注意 ...
- 赫夫曼\哈夫曼\霍夫曼编码 (Huffman Tree)
哈夫曼树 给定n个权值作为n的叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的结点离 ...
- 哈夫曼编码(Huffman coding)的那些事,(编码技术介绍和程序实现)
前言 哈夫曼编码(Huffman coding)是一种可变长的前缀码.哈夫曼编码使用的算法是David A. Huffman还是在MIT的学生时提出的,并且在1952年发表了名为<A Metho ...
- 采用霍夫曼编码(Huffman)画出字符串各字符编码的过程并求出各字符编码 --多媒体技术与应用
题目:有一个字符串:cabcedeacacdeddaaaba,问题: (1)采用霍夫曼编码画出编码的过程,并写出各字符的编码 (2)根据求得的编码,求得各编码需要的总位数 (3)求出整个字符串总编码长 ...
- 霍夫曼编码(Huffman)
题目:有一个字符串:cabcedeacacdeddaaaba,问题: (1)采用霍夫曼编码画出编码的过程,并写出各字符的编码 (2)根据求得的编码,求得各编码需要的总位数 (3)求出整个字符串总编码长 ...
- Python 算法(2) 哈夫曼编码 Huffman Encoding
这个问题原始是用来实现一个可变长度的编码问题,但可以总结成这样一个问题,假设我们有很多的叶子节点,每个节点都有一个权值w(可以是任何有意义的数值,比如它出现的概率),我们要用这些叶子节点构造一棵树,那 ...
- 霍夫曼编码(Huffman Coding)
霍夫曼编码(Huffman Coding)是一种编码方法,霍夫曼编码是可变字长编码(VLC)的一种. 霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符 ...
- 哈夫曼编码的理解(Huffman Coding)
哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,可变字长编码(VLC)的一种.Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最 ...
- HDU2527 哈夫曼编码
Safe Or Unsafe Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
随机推荐
- CS小分队第二阶段冲刺站立会议(5月27日)
昨天成果:昨日有些小意外,导致没有按照原定计划工作.昨天为扫雷游戏增加了新的失败特效,只要玩家点到地雷,所有的地雷都会依次出现两帧的爆炸效果,并伴随声音. 今日计划:排除一些现有程序的bug.. 遇到 ...
- c艹第三次作业
1.git地址,不要介意仓库名. https://github.com/b666666666666666b/elevator-schedualing 2.首先,我先说一下我是怎么实现三个电梯的. 首先 ...
- Alpha 冲刺(7/10)
队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 学习MSI.CUDA 试运行软件并调试 ...
- HDU 5203 Rikka with wood sticks 分类讨论
题目链接: hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5203 bc(chinese):http://bestcoder.hdu.edu.cn/con ...
- Markdown的基本语法
Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用.看到这里请不要被「标记」.「语言」所迷惑,Markdown 的语法十分简单.常用的标记符号也不 ...
- linux 虚拟网络模型介绍
第一种隔离模型 每一个虚拟机实例的网卡都有两个接口,一端接在虚拟机内部,一端接在宿主机内部,如上图所示eth0就是接在虚拟机内部的,而vnet0就是接在宿主机内部的,只要再创建一个虚 ...
- git向github提交时不输入账号密码
缘由:每次向github提交代码时都要输入用户名密码,太麻烦了,影响效率 解决方案: 方案一: 在你的用户目录下新建一个文本文件.git-credentials Windows:C:/Users/us ...
- 201621123037 《Java程序设计》第9周学习总结
作业09-集合与泛型z 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 这次改一个方式,就不用思维导图了,用图文结合方式来总结 1. Map三视图 键值: S ...
- ctf实验平台-成绩单
题目链接:http://120.24.86.145:8002/chengjidan/ 平台地址:http://123.206.31.85/ 第一步:暴库 id=-1' union select 1,2 ...
- (八)Jmeter怎么通过后置处理器去做关联
一.Jmeter关联的方式: Jmeter中关联可以在需要获取数据的请求上 右键-->后置处理器 选择需要的关联方式,如下图有很多种方法可以提取动态变化数据: 二.正则表达式提取器: 1.比如 ...