简单快速的哈夫曼编码

2016-01-29 12:17 88 1 收藏

简单快速的哈夫曼编码,简单快速的哈夫曼编码

【 tulaoshi.com - C语言心得技巧 】

简单快速的哈夫曼编码

作者:Hatem Mostafa
译者:happyparrot

下载源代码

介绍

本文描述在网上能够找到的最简单,最快速的哈夫曼编码。本方法不使用任何扩展动态库,比如STL或者组件。只使用简单的C函数,比如:memset,memmove,qsort,malloc,realloc和memcpy。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com)

因此,大家都会发现,理解甚至修改这个编码都是很容易的。



背景

哈夫曼压缩是个无损的压缩算法,一般用来压缩文本和程序文件。哈夫曼压缩属于可变代码长度算法一族。意思是个体符号(例如,文本文件中的字符)用一个特定长度的位序列替代。因此,在文件中出现频率高的符号,使用短的位序列,而那些很少出现的符号,则用较长的位序列。

编码使用

我用简单的C函数写这个编码是为了让它在任何地方使用都会比较方便。你可以将他们放到类中,或者直接使用这个函数。并且我使用了简单的格式,仅仅输入输出缓冲区,而不象其它文章中那样,输入输出文件。

bool CompressHuffman(BYTE *pSrc, int nSrcLen, BYTE *&pDes, int &nDesLen);bool DecompressHuffman(BYTE *pSrc, int nSrcLen, BYTE *&pDes, int &nDesLen);
要点说明

速度

为了让它(huffman.cpp)快速运行,我花了很长时间。同时,我没有使用任何动态库,比如STL或者MFC。它压缩1M数据少于100ms(P3处理器,主频1G)。

压缩

压缩代码非常简单,首先用ASCII值初始化511个哈夫曼节点:

CHuffmanNode nodes[511];for(int nCount = 0; nCount < 256; nCount++)    nodes[nCount].byAscii = nCount;
然后,计算在输入缓冲区数据中,每个ASCII码出现的频率:
for(nCount = 0; nCount < nSrcLen; nCount++)    nodes[pSrc[nCount]].nFrequency++;
然后,根据频率进行排序:
qsort(nodes, 256, sizeof(CHuffmanNode), frequencyCompare);
现在,构造哈夫曼树,获取每个ASCII码对应的位序列:
int nNodeCount = GetHuffmanTree(nodes);
构造哈夫曼树非常简单,将所有的节点放到一个队列中,用一个节点替换两个频率最低的节点,新节点的频率就是这两个节点的频率之和。这样,新节点就是两个被替换节点的父节点了。如此循环,直到队列中只剩一个节点(树根)。
// parent nodepNode = &nodes[nParentNode++];// pop first childpNode->pLeft = PopNode(pNodes, nBackNode--, false);// pop second childpNode->pRight = PopNode(pNodes, nBackNode--, true);// adjust parent of the two poped nodespNode->pLeft->pParent = pNode->pRight->pParent = pNode;// adjust parent frequencypNode->nFrequency = pNode->pLeft->nFrequency + pNode->pRight->nFrequency;
这里我用了一个好的诀窍来避免使用任何队列组件。我先前就直到ASCII码只有256个,但我分配了511个(CHuffmanNode nodes[511]),前255个记录ASCII码,而用后255个记录哈夫曼树中的父节点。并且在构造树的时候只使用一个指针数组(ChuffmanNode *pNodes[256])来指向这些节点。同样使用两个变量来操作队列索引(int nParentNode = nNodeCount;nBackNode = nNodeCount –1)。

接着,压缩的最后一步是将每个ASCII编码写入输出缓冲区中:
int nDesIndex = 0;// loop to write codesfor(nCount = 0; nCount < nSrcLen; nCount++){        *(DWORD*)(pDesPtr+(nDesIndex>>3)) |=                   nodes[pSrc[nCount]].dwCode << (nDesIndex&7);        nDesIndex += nodes[pSrc[nCount]].nCodeLength;}
(nDesIndex3): 3 以8位为界限右移后到达右边字节的前面 (nDesIndex&7): &7 得到最高位.

注意:在压缩缓冲区中,我们必须保存哈夫曼树的节点以及位序列,这样我们才能在解压缩时重新构造哈夫曼树(只需保存ASCII值和对应的位序列)。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com)

解压缩

解压

来源:http://www.tulaoshi.com/n/20160129/1485404.html

延伸阅读
《哈真黑暗密语》快速获得红色装备方法 几个小时前还郁闷呢,刷了无数次第三幕火BOSS就是不出红色装,然后去刷第二幕蜘蛛BOSS,结果3次就掉落一个红色项链,拾起一看, 哈哈, 战士的,需要力量70!然后马上又刷一遍,掉落一红色项链,法师的,这俩项链的共有属性就是Life+2000,所有技能+1 然后刚刚又刷了一个红色的盾牌,也是life+2000 &nbs...
《哈真:黑暗密语》快速获取红色装备方法 几个小时前还郁闷呢,刷了无数次第三幕火BOSS就是不出红色装,然后去刷第二幕蜘蛛BOSS,结果3次就掉落一个红色项链,拾起一看, 哈哈, 战士的,需要力量70!然后马上又刷一遍,掉落一红色项链,法师的,这俩项链的共有属性就是Life+2000,所有技能+1 然后刚刚又刷了一个红色的盾牌,也是life+2000 蜘...
1.规范简介?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 本规范主要规定Delphi源程序在书写过程中所应遵循的规则及注意事项。编写该规范的目的是使公司软件开发人员的源代码书写习惯保持一致。这样做可以使每一个组员都可以理解其它组员的代码,以便于源代码的二次开发记忆系统的维护。   ...
开始编码之前 在VisualBasic中创建应用程序的最重要的(又往往为人忽视的)部分是设计阶段。需要为应用程序设计一个用户界面,这是显然的;但需要设计代码的结构就不那么显然了。构造应用程序的方法不同,可造成应用程序的性能及代码的可维护性、可使用性不同。 VisualBasic应用程序的代码是用分层方式组织的。典型应用程序包括...
标签: 花卉
曼珠沙华(Lycorisradiata),又名彼岸花。历史上彼岸花在中国被叫做金灯、赤箭或者无义草。下面来小编将为大家介绍 曼珠沙华的传说 及曼珠沙华的花语。 一、曼珠沙华的传说 传说,很久很久以前,某个城市的边缘开满了大片大片的曼珠沙华,也就是彼岸花,它的花香有一种魔力,可以让人想起自己前世的事情。守护彼岸花的是...

经验教程

622

收藏

35
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部