五种数据压缩算法

  • 格式:doc
  • 大小:163.42 KB
  • 文档页数:60

. . . .

. . . . .  哈弗曼编码

A method for the construction of minimum-re-dundancy codes,

耿1数据结构1:高等教育,2005:182—190

严蔚敏,吴伟民.数据结构(C语言版)[M].:清华大学,1997.

桂,林其伟,东华.信息论与编码技术[M].:清华大学,2007.

大有,唐海鹰,舒,等.数据结构[M].:高等教育,2001

 压缩实现

速度要求

为了让它(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;

}

 程序实现

费诺编码

#include

#include

#include

#include . . . .

. . . . . #define M 100

typedef struct Fano_Node

{

char ch;

float weight;

}FanoNode[M];

typedef struct node

{

int start;

int end;

struct node *next;

}LinkQueueNode;

typedef struct

{

LinkQueueNode *front;

LinkQueueNode *rear;

}LinkQueue;

//建立队列

void EnterQueue(LinkQueue *q,int s,int e)

{

LinkQueueNode *NewNode;

//生成新节点

NewNode=(LinkQueueNode*)malloc(sizeof( LinkQueueNode ));

if(NewNode!=NULL)

{

NewNode->start=s;

NewNode->end=e; . . . .

. . . . . NewNode->next=NULL;

q->rear->next=NewNode;

q->rear=NewNode;

}

else

{

printf("Error!");

exit(-1);

}

}

//按权分组

void Divide(FanoNode f,int s,int *m,int e)

{

int i;

float sum,sum1;

sum=0;

for(i=s;i<=e;i++)

sum+=f[i].weight;//

*m=s;

sum1=0;

for(i=s;i

{

sum1+=f[i].weight;

*m=fabs(sum-2*sum1)>fabs(sum-2*sum1-2*f[i+1].weight)?(i+1):*m;

if(*m==i) break;

}

} . . . .

. . . . . void main()

{

int i,j,n,max,m,h[M];

int sta,end;

float w;

char c,fc[M][M];

FanoNode FN;

LinkQueueNode *p;

LinkQueue *Q;

//初始化队Q

Q=(LinkQueue *)malloc(sizeof(LinkQueue));

Q->front=(LinkQueueNode*)malloc(sizeof(LinkQueueNode));

Q->rear=Q->front;

Q->front->next=NULL;

printf("\t***FanoCoding***\n");

printf("Please input the number of node:");

//输入信息

scanf("%d",&n);

//超过定义M,退出

if(n>=M)

{

printf(">=%d",M);

exit(-1);

}

i=1; //从第二个元素开始录入

while(i<=n)

{ . . . .

. . . . . printf("%d weight and node:",i);

scanf("%f %c",&FN[i].weight,&FN[i].ch);

for(j=1;j

{

if(FN[i].ch==FN[j].ch)//查找重复

{

printf("Same node!!!\n"); break;

}

}

if(i==j)

i++;

}

//排序(降序)

for(i=1;i<=n;i++)

{

max=i+1;

for(j=max;j<=n;j++)

max=FN[max].weight

if(FN[i].weight

{

w=FN[i].weight;

FN[i].weight=FN[max].weight;

FN[max].weight=w;

c=FN[i].ch;

FN[i].ch=FN[max].ch;

FN[max].ch=c;

}