最简哈夫曼树


请输入要查询的词条内容:

最简哈夫曼树




简介


首先要了解树的概念。树并不是指植物,而是一种数据结构,因为其存放方式颇有点象一棵树有树叉因而称为树。最简哈夫曼树是由德国数学家冯 哈夫曼 发现的,此树的特点就是引出的路程最短。它的形状单支形式。

数对于编程具有重大的意义,是某些看似不可能完成或是很难完成的任务较为简单,有条理的完成。

首先要了解树的概念。树并不是指植物,而是一种数据结构,因为其存放方式颇有点象一棵树有树叉因而称为树。

哈夫曼树又称最优二叉树,是一种带权路径长最短的树。树的路径长度是从树根到每一个叶子之间的路径长度之和。节点的带树路径长度为从该节点到树根之间的路径长度与该节点权(比如字符在某串中的使用频率)的乘积。

应用


#include<stdio.h>

最简哈夫曼树

#include<stdlib.h>

#include<string.h>

#include<conio.h>a

#include<graphics.h>

#define MAXVALUE 200 /*权值的最大值*/

#define MAXB99v 30 /*最大的编码位数*/

#define MAXNODE 30 /*初始的最大的结点数*/

struct haffnode

{char data;

int weight;

int flag;

int parent; /*双亲结点的下标*/int leftchild; /*左孩子下标*/

int rightchild; /*右孩子下标*/

};

struct haffcode

{int bit[MAXNODE];

int start; /*编码的起始下标*/

char data;

int weight; /*字符权值*/

};

构建


/*函数说明*/

最简哈夫曼树

/************************************************************************/

void pprintf(struct haffcode haffcode[],int n);

/*输出函数*/

void haffmantree(int weight[],int n,struct haffnode hafftree[],char data[]);

/*建立哈夫曼树*/

void haffmancode(struct haffnode hafftree[],int n,struct haffcode haffcode[]);

/*求哈夫曼编码*/

void test(struct haffcode haffcode[],int n);

/*测试函数*/

void end();

/*结束界面函数*/

/************************************************************************/void haffmantree(int weight[],int n,struct haffnode hafftree[],char data[])

/*建立叶结点个数为n,权值数组为weight[]的哈夫曼树*/

{int i,j,m1,m2,x1,x2;

/*哈夫曼树hafftree[]初始化,n个叶结点共有2n-1个结点*/

for(i=0;i<2*n-1;i++)

{if(i<n) {hafftree[i].data=data[i];

hafftree[i].weight=weight[i]; /*叶结点*/

}

else {hafftree[i].weight=0; /*非叶结点*/

hafftree[i].data=''\\0'';

}

hafftree[i].parent=0; /*初始化没有双亲结点*/

hafftree[i].flag=0;

hafftree[i].leftchild=-1;

sp; hafftree[i].rightchild=-1;

}

for(i=0;i<n-1;i++) /*构造哈夫曼树n-1个非叶结点*/

编码


本文描述在网上能够找到的最简单,最快速的哈夫曼编码。本方法不使用任何扩展动态库,比如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 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 )

两个变量来操作队列索引(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;}(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;}(nDesIndex>>3): >>3 以8位为界限右移后到达右边字节的前面 (nDesIndex&7): &7 得到最高位.

相关分词: 最简 哈夫曼 哈夫 夫曼