五种数据压缩算法.docx

上传人:b****6 文档编号:6861182 上传时间:2023-01-11 格式:DOCX 页数:52 大小:97.80KB
下载 相关 举报
五种数据压缩算法.docx_第1页
第1页 / 共52页
五种数据压缩算法.docx_第2页
第2页 / 共52页
五种数据压缩算法.docx_第3页
第3页 / 共52页
五种数据压缩算法.docx_第4页
第4页 / 共52页
五种数据压缩算法.docx_第5页
第5页 / 共52页
点击查看更多>>
下载资源
资源描述

五种数据压缩算法.docx

《五种数据压缩算法.docx》由会员分享,可在线阅读,更多相关《五种数据压缩算法.docx(52页珍藏版)》请在冰豆网上搜索。

五种数据压缩算法.docx

五种数据压缩算法

⏹哈弗曼编码

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个哈夫曼节点:

CHuffmanNodenodes[511];

for(intnCount=0;nCount<256;nCount++)

nodes[nCount].byAscii=nCount;

其次,计算在输入缓冲区数据中,每个ASCII码出现的频率:

for(nCount=0;nCount

nodes[pSrc[nCount]].nFrequency++;

然后,根据频率进行排序:

qsort(nodes,256,sizeof(CHuffmanNode),frequencyCompare);

哈夫曼树,获取每个ASCII码对应的位序列:

intnNodeCount=GetHuffmanTree(nodes);

构造哈夫曼树

构造哈夫曼树非常简单,将所有的节点放到一个队列中,用一个节点替换两个频率最低的节点,新节点的频率就是这两个节点的频率之和。

这样,新节点就是两个被替换节点的父节点了。

如此循环,直到队列中只剩一个节点(树根)。

//parentnode

pNode=&nodes[nParentNode++];

//popfirstchild

pNode->pLeft=PopNode(pNodes,nBackNode--,false);

//popsecondchild

pNode->pRight=PopNode(pNodes,nBackNode--,true);

//adjustparentofthetwopopednodes

pNode->pLeft->pParent=pNode->pRight->pParent=pNode;

//adjustparentfrequency

pNode->nFrequency=pNode->pLeft->nFrequency+pNode->pRight->nFrequency

注意事项

有一个好的诀窍来避免使用任何队列组件。

ASCII码只有256个,但实际分配了511个(CHuffmanNodenodes[511]),前255个记录ASCII码,而用后255个记录哈夫曼树中的父节点。

并且在构造树的时候只使用一个指针数组(ChuffmanNode*pNodes[256])来指向这些节点。

同样使用两个变量来操作队列索引(intnParentNode=nNodeCount;nBackNode=nNodeCount–1)。

接着,压缩的最后一步是将每个ASCII编码写入输出缓冲区中:

intnDesIndex=0;

//looptowritecodes

for(nCount=0;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值添加到输出缓冲区中:

intnDesIndex=0;

DWORDnCode;

while(nDesIndex

{

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

#defineM100

typedefstructFano_Node

{

charch;

floatweight;

}FanoNode[M];

typedefstructnode

{

intstart;

intend;

structnode*next;

}LinkQueueNode;

typedefstruct

{

LinkQueueNode*front;

LinkQueueNode*rear;

}LinkQueue;

//建立队列

voidEnterQueue(LinkQueue*q,ints,inte)

{

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);

}

}

//按权分组

voidDivide(FanoNodef,ints,int*m,inte)

{

inti;

floatsum,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;

}

}

voidmain()

{

inti,j,n,max,m,h[M];

intsta,end;

floatw;

charc,fc[M][M];

FanoNodeFN;

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("Pleaseinputthenumberofnode:

");

//输入信息

scanf("%d",&n);

//超过定义M,退出

if(n>=M)

{

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

exit(-1);

}

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

while(i<=n)

{

printf("%dweightandnode:

",i);

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

for(j=1;j

{

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

{

printf("Samenode!

!

!

\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

j:

max;

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;

}

}

for(i=1;i<=n;i++)//初始化h

h[i]=0;

EnterQueue(Q,1,n);//1和n进队

while(Q->front->next!

=NULL)

{

p=Q->front->next;//出队

Q->front->next=p->next;

if(p==Q->rear)

Q->rear=Q->front;

sta=p->start;

end=p->end;

free(p);

Divide(FN,sta,&m,end);/*按权分组*/

for(i=sta;i<=m;i++)

{

fc[i][h[i]]='0';

++h[i];

}

if(sta!

=m)

EnterQueue(Q,sta,m);

else

fc[sta][h[sta]]='\0';

for(i=m+1;i<=end;i++)

{

fc[i][h[i]]='1';

++h[i];

}

if(m==sta&&(m+1)==end)

//如果分组后首元素的下标与中间元素的相等,

//并且和最后元素的下标相差为1,则编码码字字符串结束

{

fc[m][h[m]]='\0';

fc[end][h[end]]='\0';

}

else

EnterQueue(Q,m+1,end);

}

for(i=1;i<=n;i++)/*打印编码信息*/

{

printf("%c:

",FN[i].ch);

printf("%s\n",fc[i]);

}

system("pause");

}[4]

编码解码

#include

#include

#include

#defineN100

#defineM2*N-1

typedefchar*HuffmanCode[2*M];//haffman编码

typedefstruct

{

intweight;//权值

intparent;//父节节点

intLChild;//左子节点

intRChild;//右子节点

}HTNode,Huffman[M+1];//huffman树

typedefstructNode

{

intweight;//叶子结点的权值

charc;//叶子结点

intnum;//叶子结点的二进制码的长度

}WNode,WeightNode[N];

/***产生叶子结点的字符和权值***/

voidCreateWeight(charch[],int*s,WeightNodeCW,int*p)

{

inti,j,k;

inttag;

*p=0;//叶子节点个数

//统计字符出现个数,放入CW

for(i=0;ch[i]!

='\0';i++)

{

tag=1;

for(j=0;j

if(ch[j]==ch[i])

{

tag=0;

break;

}

if(tag)

{

CW[++*p].c=ch[i];

CW[*p].weight=1;

for(k=i+1;ch[k]!

='\0';k++)

if(ch[i]==ch[k])

CW[*p].weight++;//权值累加

}

}

*s=i;//字符串长度

}

/********创建HuffmanTree********/

voidCreateHuffmanTree(Huffmanht,WeightNodew,intn)

{

inti,j;

ints1,s2;

//初始化哈夫曼树

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

{

ht[i].weight=w[i].weight;

ht[i].parent=0;

ht[i].LChild=0;

ht[i].RChild=0;

}

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

{

ht[i].weight=0;

ht[i].parent=0;

ht[i].LChild=0;

ht[i].RChild=0;

}

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

{

for(j=1;j<=i-1;j++)

if(!

ht[j].parent)

break;

s1=j;//找到第一个双亲为零的结点

for(;j<=i-1;j++)

if(!

ht[j].parent)

s1=ht[s1].weight>ht[j].weight?

j:

s1;

ht[s1].parent=i;

ht[i].LChild=s1;

for(j=1;j<=i-1;j++)

if(!

ht[j].parent)

break;

s2=j;//找到第二个双亲为零的结点

for(;j<=i-1;j++)

if(!

ht[j].parent)

s2=ht[s2].weight>ht[j].weight?

j:

s2;

ht[s2].parent=i;

ht[i].RChild=s2;

ht[i].weight=ht[s1].weight+ht[s2].weight;//权值累加

}

}

/***********叶子结点的编码***********/

voidCrtHuffmanNodeCode(Huffmanht,charch[],HuffmanCodeh,WeightNodeweight,intm,intn)

{

inti,c,p,start;

char*cd;

cd=(char*)malloc(n*sizeof(char));

cd[n-1]='\0';//末尾置0

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

{

start=n-1;//cd串每次从末尾开始

c=i;

p=ht[i].parent;//p在n+1至2n-1

while(p)//沿父亲方向遍历,直到为0

{

start--;//依次向前置值

if(ht[p].LChild==c)//与左子相同,置0

cd[start]='0';

else//否则置1

cd[start]='1';

c=p;

p=ht[p].parent;

}

weight[i].num=n-start;//二进制码的长度(包含末尾0)

h[i]=(char*)malloc((n-start)*sizeof(char));

strcpy(h[i],&cd[start]);//将二进制字符串拷贝到指针数组h中

}

free(cd);//释放cd存

system("pause");

}

/*********所有字符的编码*********/

voidCrtHuffmanCode(charch[],HuffmanCodeh,HuffmanCodehc,WeightNodeweight,intn,intm)

{

inti,k;

for(i=0;i

{

for(k=1;k<=n;k++)/*从weight[k].c中查找与ch[i]相等的下标K*/

if(ch[i]==weight[k].c)

break;

hc[i]=(char*)malloc((weight[k].num)*sizeof(char));

strcpy(hc[i],h[k]);//拷贝二进制编码

}

}

/*****解码*****/

voidTrsHuffmanTree(Huffmanht,WeightNodew,HuffmanCodehc,intn,intm)

{

inti=0,j,p;

printf("***StringInformation***\n");

while(i

{

p=2*n-1;//从父亲节点向下遍历直到叶子节点

for(j=0;hc[i][j]!

='\0';j++)

{

if(hc[i][j]=='0')

p=ht[p].LChild;

else

p=ht[p].RChild;

}

printf("%c",w[p].c);/*打印原信息*/

i++;

}

}

/*****释放huffman编码存*****/

voidFreeHuffmanCode(HuffmanCodeh,HuffmanCodehc,intn,intm)

{

inti;

for(i=1;i<=n;i++)//释放叶子结点的编码

free(h[i]);

for(i=0;i

free(hc[i]);

}

voidmain()

{

inti,n=0;/*n为叶子结点的个数*/

intm=0;/*m为字符串ch[]的长度*/

charch[N];/*ch[N]存放输入的字符串*/

Huffmanht;/*Huffman二叉数*/

HuffmanCodeh,hc;/*h存放叶子结点的编码,hc存放所有结点的编码*/

WeightNodeweight;/*存放叶子结点的信息*/

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

printf("pleaseinputinformation:

");

gets(ch);/*输入字符串*/

CreateWeight(ch,&m,weight,&n);/*产生叶子结点信息,m为字符串ch[]的长度*/

printf("***WeightInformation***\nNode");

for(i=1;i<=n;i++)/*输出叶子结点的字符与权值*/

printf("%c",weight[i].c);

printf("\nWeight");

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

printf("%d",weight[i].weight);

CreateHuffmanTree(ht,weight,n);/*产生Huffman树*/

printf("\n***HuffamnTreeInformation***\n");

printf("\ti\tweight\tparent\tLChild\tRChild\n");

for(i=1;i<=2*n-1;i++)/*打印Huffman树的信息*/

printf("\t%d\t%d\t%d\t%d\t%d\n",i,ht[i].weight,ht[i].parent,ht[i].LChild,ht[i].RChild);

CrtHuffmanNodeCode(ht,ch,h,weight,m,n);/*叶子结点的编码*/

printf("***NodeCode***\n");/*打印叶子结点的编码*/

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

{

printf("\t%c:

",weight[i].c);

printf("%s\n",h[i]);

}

CrtHuffmanCode(ch,h,hc,weight,n,m);/*所有字符的编码*/

printf("***StringCode***\n");/*打印字符串的编码*/

for(i=0;i

printf("%s",hc[i]);

system("pause");

TrsHuffmanTree(ht,weight,hc,n,m);/*解码*/

FreeHuffmanCode(h,hc,n,m);

system("pause");

}[5]

Matlab实现

Matlab中简易实现Huffman编译码:

n=input('Pleaseinputthetotalnumber:

');

hf=zeros(2*n-1,5);

hq=[];

forki=1:

n

hf(ki,1)=ki;

hf(ki,2)=input('Pleaseinputthefrequency:

');

hq=[hq,hf(ki,2)];

end

forki=n+1:

2*n-1

hf(ki,1)=ki;

mhq1=min(hq);

m=size(hq);

m=m(:

2);

k=1;

whilek<=m%delmin1

ifhq(:

k)==mhq1

hq=[hq(:

1:

(k-1))hq(:

(k+1):

m)];

m=m-1;

break

else

k=k+1;

end

end

k=1;

whilehf(k,2)~=mhq1|hf(k,5)==1%findmin1location

k=k+1;

end

hf(k,5)=1;

k1=k;

mhq2=min(hq);

k=1;

whilek<=m%delmin2

ifhq(:

k)==mhq2

hq=[hq(:

1:

(k-1))hq(:

(k+1):

m)];

m=m-1;

break

else

k=k+1;

end

end

k=1;

whilehf(k,2)~=mhq2|hf(k,5)==1%findmin2location

k=k+1;

end

hf(k,5)=1;

k2=k;

hf(ki,2)=mhq1+mhq2;

hf(ki,3)=k1;

hf(ki,4)=k2;

hq=[hqhf(ki,2)];

end

clc

choose=input('Pleasechoosewhatyouwant:

\n1:

Encoding\n2:

Decoding\n3:

.Exit\n');

whilechoose==1|choose==2

ifchoose==1

a=input('PleaseinputtheletteryouwanttoEncoding:

');

k=1;

whilehf(k,2

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1