霍夫曼(Huffman)编码学习的重点和难点是什么

作者&投稿:彭馨 (若有异议请与网页底部的电邮联系)
哈夫曼编码的原理~

设某信源产生有五种符号u1、u2、u3、u4和u5,对应概率P1=0.4,P2=0.1,P3=P4=0.2,P5=0.1。首先,将符号按照概率由大到小排队,如图所示。编码时,从最小概率的两个符号开始,可选其中一个支 路为0,另一支路为1。这里,我们选上支路为0,下支路为1。再将已编码的两支路的概率合并,并重新排队。多次重复使用上述方法直至合并概率归一时为止。从图(a)和(b)可以看出,两者虽平均码长相等,但同一符号可以有不同的码长,即编码方法并不唯一,其原因是两支路概率合并后重新排队时,可能出现几个支路概率相等,造成排队方法不唯一。一般,若将新合并后的支路排到等概率的最上支路,将有利于缩短码长方差,且编出的码更接近于等长码。这里图(a)的编码比(b)好。赫夫曼码的码字(各符号的代码是异前置码字,即任一码字不会是另一码宇的前面部分,这使各码字可以连在一起传送,中间不需另加隔离符号,只要传送时不出错,收端仍可分离各个码字,不致混淆。实际应用中,除采用定时清洗以消除误差扩散和采用缓冲存储以解决速率匹配以外,主要问题是解决小符号集合的统计匹配,例如黑(1)、白(0)传真信源的统计匹配,采用0和1不同长度游程组成扩大的符号集合信源。游程,指相同码元的长度(如二进码中连续的一串0或一串1的长度或个数)。按照CCITT标准,需要统计2×1728种游程(长度),这样,实现时的存储量太大。事实上长游程的概率很小,故CCITT还规定:若l表示游程长度,则l=64q+r。其中q称主码,r为基码。编码时,不小于64的游程长度由主码和基码组成。而当l为64的整数倍时,只用主码的代码,已不存在基码的代码。长游程的主码和基码均用赫夫曼规则进行编码,这称为修正赫夫曼码,其结果有表可查。该方法已广泛应用于文件传真机中。


哈夫曼编码(Huffman Coding)是一种编码方式,以哈夫曼树—即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。 在计算机信息处理中,“哈夫曼编码”是一种一致性编码法(又称"熵编码法"),用于数据的无损耗压缩。这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。这种方法是由David.A.Huffman发展起来的。 例如,在英文中,e的出现概率很高,而z的出现概率则最低。当利用哈夫曼编码对一篇英文进行压缩时,e极有可能用一个位(bit)来表示,而z则可能花去25个位(不是26)。用普通的表示方法时,每个英文字母均占用一个字节(byte),即8个位。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。

本文描述在网上能够找到的最简单,最快速的哈夫曼编码。本方法不使用任何扩展动态库,比如STL或者组件。只使用简单的C函数,比如:memset,memmove,qsort,malloc,realloc和memcpy。
因此,大家都会发现,理解甚至修改这个编码都是很容易的。

背景
哈夫曼压缩是个无损的压缩算法,一般用来压缩文本和程序文件。哈夫曼压缩属于可变代码长度算法一族。意思是个体符号(例如,文本文件中的字符)用一个特定长度的位序列替代。因此,在文件中出现频率高的符号,使用短的位序列,而那些很少出现的符号,则用较长的位序列。
编码使用
我用简单的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 node
pNode = &nodes[nParentNode++];
// pop first child
pNode->pLeft = PopNode(pNodes, nBackNode--, false);
// pop second child
pNode->pRight = PopNode(pNodes, nBackNode--, true);
// adjust parent of the two poped nodes
pNode->pLeft->pParent = pNode->pRight->pParent = pNode;
// adjust parent frequency
pNode->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 codes
for(nCount = 0; nCount < nSrcLen; nCount++)
{
*(DWORD*)(pDesPtr+(nDesIndex>>3)) |=
nodes[pSrc[nCount]].dwCode << (nDesIndex&7);
nDesIndex += nodes[pSrc[nCount]].nCodeLength;
}
(nDesIndex>>3): >>3 以8位为界限右移后到达右边字节的前面
(nDesIndex&7): &7 得到最高位.
注意:在压缩缓冲区中,我们必须保存哈夫曼树的节点以及位序列,这样我们才能在解压缩时重新构造哈夫曼树(只需保存ASCII值和对应的位序列)。
解压缩
解压缩比构造哈夫曼树要简单的多,将输入缓冲区中的每个编码用对应的ASCII码逐个替换就可以了。只要记住,这里的输入缓冲区是一个包含每个ASCII值的编码的位流。因此,为了用ASCII值替换编码,我们必须用位流搜索哈夫曼树,直到发现一个叶节点,然后将它的ASCII值添加到输出缓冲区中:
int nDesIndex = 0;
DWORD nCode;
while(nDesIndex < nDesLen)
{
nCode = (*(DWORD*)(pSrc+(nSrcIndex>>3)))>>(nSrcIndex&7);
pNode = pRoot;
while(pNode->pLeft)
{
pNode = (nCode&1) ? pNode->pRight : pNode->pLeft;
nCode >>= 1;
nSrcIndex++;
}
pDes[nDesIndex++] = pNode->byAscii;
}


利用 数据结构 实现 哈夫曼编码\/译码实现
void HaffmanCode(HNodetype HuffNode[],HCodetype HuffCode[],Total *total);\/\/建立哈夫曼编码void writing_HCode(HNodetype HuffNode[],HCodetype HuffCode[],Total *total);\/\/将编码规则写进文件void lock(Message *message,HNodetype HuffNode[],HCodetype HuffCode[],Total *total,Locking *locking);\/\/...

写个哈夫曼编码译码程序 数据结构 c++
&cd[start]); }  delete(cd);} void bianma(HuffmanCode HC,char *a,char *d,char *bc) {int m1=0,m2=0; 

谁会用C语言编程???
printf("\\n ===the huffmatree===\\n");for(i=1;i<=m;++i)if(i<=29)printf("\\n data: %2c weight: %-4d parent: %-3d lchild: %-3d rchild: %-3d", HT[i].data,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);else printf("\\n data: no weight...

宜州市19872615471: 什么是哈夫曼编码 -
游罡佳乐: 哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种.Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码).

宜州市19872615471: 哈夫曼编码原理 -
游罡佳乐: 原发布者:a2420092945 Huffman树及其应用一、最优二叉树(霍夫曼树)预备知识:若干术语路d径:由一结点到另一结点间的分支所构成a→e的路径长度=2beacfg路径长度:路径上的分支数目树长度=10树的路径长度:从树根到每一结点的...

宜州市19872615471: 霍夫曼编码难学吗?需要什么基础? -
游罡佳乐: 不难学.霍夫曼编码目的就是压缩.原理较简单,简单的说,就是对最常出现的字母,采用最短的编码;对最少出现的字母,采用最长的编码.从而达到无损压缩的目的.建议你看看维 基百 科的霍夫曼编码词条.里面既讲到了原理,又有C++源代码的例子.当然你需要有C++的基础,也需要有少许STL的容器和算法的基础,此外还需要数据结构中的二叉树的基础.

宜州市19872615471: 什么是霍夫曼编码? -
游罡佳乐: 霍夫曼(Huffman)编码原理 霍夫曼(Huffman)编码是1952年为文本文件而建立,是一种统计编码.属于无损压缩编码. 霍夫曼编码的码长是变化的,对于出现频率高的信息,编码的长度较短;而对于出现频率低的信息,编码长度较长.这样...

宜州市19872615471: 霍夫曼编码的思想是什么 -
游罡佳乐: 哈夫曼编码(Huffman Coding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种.uffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长 度最短的码字,有时称之为最佳编码,一般就叫作Huffman...

宜州市19872615471: 霍夫曼编码 -
游罡佳乐: 霍夫曼(Huffman)在1952年提出 是一种从下到上的编码方法,即从叶子逐步往上生成编码树 编码算法实际上是一个构造霍夫曼树的过程(根据资料出现频率的多寡来建造的树,霍夫曼树的树叶节点用以储存资料元素 ( Data Element ) ,若...

宜州市19872615471: Huffman编码的算法 -
游罡佳乐: 霍夫曼编/译码器c/c++代码#include#include"stdio.h" #include"stdlib.h"#include"string.h"typedef char ElemType;typedef struct { ElemType elem; unsigned int m_weight; unsigned int parent,lchild,rchild;}HTNode,*HuffmanTree;typedef char** ...

宜州市19872615471: 哈夫曼编码的发展历史 -
游罡佳乐: 1951年,哈夫曼和他在MIT信息论的同学需要选择是完成学期报告还是期末考试.导师Robert M. Fano给他们的学期报告的题目是,寻找最有效的二进制编码.由于无法证明哪个已有编码是最有效的,哈夫曼放弃对已有编码的研究,转向新的探...

宜州市19872615471: 什么是赫夫曼树?
游罡佳乐: 1、是一种利用二叉树实现的编码原理 霍夫曼(Huffman)编码原理 霍夫曼(Huffman)编码是1952年为文本文件而建立,是一种统计编码.属于无损压缩编码. 霍夫曼编码的码长是变化的,对于出现频率高的信息,编码的长度较短;而对于出...

宜州市19872615471: Huffman编码 -
游罡佳乐: 先分析个字符的权值:a=3,b=7,c=2,d=3,e=5生成一棵霍夫曼树,得到各字符的编码:a=110,b=0,c=1111,d=1110,e=10平均码长为46/15

你可能想看的相关专题

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网