五种数据压缩算法Word格式.docx
《五种数据压缩算法Word格式.docx》由会员分享,可在线阅读,更多相关《五种数据压缩算法Word格式.docx(52页珍藏版)》请在冰豆网上搜索。
pLeft->
pParent=pNode->
pRight->
pParent=pNode;
//adjustparentfrequency
nFrequency=pNode->
nFrequency+pNode->
nFrequency
注意事项
有一个好的诀窍来避免使用任何队列组件。
ASCII码只有256个,但实际分配了511个(CHuffmanNodenodes[511]),前255个记录ASCII码,而用后255个记录哈夫曼树中的父节点。
并且在构造树的时候只使用一个指针数组(ChuffmanNode*pNodes[256])来指向这些节点。
同样使用两个变量来操作队列索引(intnParentNode=nNodeCount;
nBackNode=nNodeCount–1)。
接着,压缩的最后一步是将每个ASCII编码写入输出缓冲区中:
intnDesIndex=0;
//looptowritecodes
{
*(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值添加到输出缓冲区中:
DWORDnCode;
while(nDesIndex<
nDesLen)
nCode=(*(DWORD*)(pSrc+(nSrcIndex>
3)))>
(nSrcIndex&
pNode=pRoot;
while(pNode->
pLeft)
pNode=(nCode&
1)?
pNode->
pRight:
pLeft;
nCode>
=1;
nSrcIndex++;
pDes[nDesIndex++]=pNode->
byAscii;
✧程序实现
费诺编码
#include<
stdio.h>
stdlib.h>
string.h>
math.h>
#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;
end=e;
next=NULL;
q->
rear->
next=NewNode;
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;
e;
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));
rear=Q->
front;
front->
\t***FanoCoding***\n"
Pleaseinputthenumberofnode:
//输入信息
scanf("
%d"
&
n);
//超过定义M,退出
if(n>
=M)
=%d"
M);
i=1;
//从第二个元素开始录入
while(i<
=n)
%dweightandnode:
i);
%f%c"
FN[i].weight,&
FN[i].ch);
for(j=1;
j<
i;
j++)
if(FN[i].ch==FN[j].ch)//查找重复
Samenode!
!
\n"
break;
if(i==j)
i++;
//排序(降序)
for(i=1;
=n;
max=i+1;
for(j=max;
max=FN[max].weight<
FN[j].weight?
j:
max;
if(FN[i].weight<
FN[max].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;
i++)//初始化h
h[i]=0;
EnterQueue(Q,1,n);
//1和n进队
while(Q->
next!
p=Q->
next;
//出队
next=p->
if(p==Q->
rear)
sta=p->
start;
end=p->
end;
free(p);
Divide(FN,sta,&
m,end);
/*按权分组*/
for(i=sta;
=m;
fc[i][h[i]]='
0'
;
++h[i];
if(sta!
=m)
EnterQueue(Q,sta,m);
fc[sta][h[sta]]='
\0'
for(i=m+1;
=end;
1'
if(m==sta&
&
(m+1)==end)
//如果分组后首元素的下标与中间元素的相等,
//并且和最后元素的下标相差为1,则编码码字字符串结束
fc[m][h[m]]='
fc[end][h[end]]='
EnterQueue(Q,m+1,end);
i++)/*打印编码信息*/
%c:
FN[i].ch);
%s\n"
fc[i]);
system("
pause"
}[4]
编码解码
#defineN100
#defineM2*N-1
typedefchar*HuffmanCode[2*M];
//haffman编码
intweight;
//权值
intparent;
//父节节点
intLChild;
//左子节点
intRChild;
//右子节点
}HTNode,Huffman[M+1];
//huffman树
typedefstructNode
//叶子结点的权值
charc;
//叶子结点
intnum;
//叶子结点的二进制码的长度
}WNode,WeightNode[N];
/***产生叶子结点的字符和权值***/
voidCreateWeight(charch[],int*s,WeightNodeCW,int*p)
inti,j,k;
inttag;
*p=0;
//叶子节点个数
//统计字符出现个数,放入CW
for(i=0;
ch[i]!
='
tag=1;
for(j=0;
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]!
k++)
if(ch[i]==ch[k])
CW[*p].weight++;
//权值累加
*s=i;
//字符串长度
/********创建HuffmanTree********/
voidCreateHuffmanTree(Huffmanht,WeightNodew,intn)
inti,j;
ints1,s2;
//初始化哈夫曼树
ht[i].weight=w[i].weight;
ht[i].parent=0;
ht[i].LChild=0;
ht[i].RChild=0;
for(i=n+1;
=2*n-1;
ht[i].weight=0;
=i-1;
if(!
ht[j].parent)
s1=j;
//找到第一个双亲为零的结点
for(;
s1=ht[s1].weight>
ht[j].weight?
s1;
ht[s1].parent=i;
ht[i].LChild=s1;
s2=j;
//找到第二个双亲为零的结点
s2=ht[s2].weight>
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
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]='
else//否则置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存
/*********所有字符的编码*********/
voidCrtHuffmanCode(charch[],HuffmanCodeh,HuffmanCodehc,WeightNodeweight,intn,intm)
inti,k;
m;
for(k=1;
k<
k++)/*从weight[k].c中查找与ch[i]相等的下标K*/
if(ch[i]==weight[k].c)
hc[i]=(char*)malloc((weight[k].num)*sizeof(char));
strcpy(hc[i],h[k]);
//拷贝二进制编码
/*****解码*****/
voidTrsHuffmanTree(Huffmanht,WeightNodew,HuffmanCodehc,intn,intm)
inti=0,j,p;
***StringInformation***\n"
m)
p=2*n-1;
//从父亲节点向下遍历直到叶子节点
hc[i][j]!
if(hc[i][j]=='
)
p=ht[p].LChild;
p=ht[p].RChild;
%c"
w[p].c);
/*打印原信息*/
/*****释放huffman编码存*****/
voidFreeHuffmanCode(HuffmanCodeh,HuffmanCodehc,intn,intm)
i++)//释放叶子结点的编码
free(h[i]);
i++)//释放所有结点的编码
free(hc[i]);
inti,n=0;
/*n为叶子结点的个数*/
intm=0;
/*m为字符串ch[]的长度*/
charch[N];
/*ch[N]存放输入的字符串*/
Huffmanht;
/*Huffman二叉数*/
HuffmanCodeh,hc;
/*h存放叶子结点的编码,hc存放所有结点的编码*/
WeightNodeweight;
/*存放叶子结点的信息*/
\t***HuffmanCoding***\n"
pleaseinputinformation:
gets(ch);
/*输入字符串*/
CreateWeight(ch,&
m,weight,&
/*产生叶子结点信息,m为字符串ch[]的长度*/
***WeightInformation***\nNode"
i++)/*输出叶子结点的字符与权值*/
%c"
weight[i].c);
\nWeight"
%d"
weight[i].weight);
CreateHuffmanTree(ht,weight,n);
/*产生Huffman树*/
\n***HuffamnTreeInformation***\n"
\ti\tweight\tparent\tLChild\tRChild\n"
i++)/*打印Huffman树的信息*/
\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);
/*叶子结点的编码*/
***NodeCode***\n"
/*打印叶子结点的编码*/
\t%c:
h[i]);
CrtHuffmanCode(ch,h,hc,weight,n,m);
/*所有字符的编码*/
***StringCode***\n"
/*打印字符串的编码*/
%s"
hc[i]);
TrsHuffmanTree(ht,weight,hc,n,m);
/*解码*/
FreeHuffmanCode(h,hc,n,m);
}[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
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
k=k+1;
whilehf(k,2)~=mhq1|hf(k,5)==1%findmin1location
hf(k,5)=1;
k1=k;
mhq2=min(hq);
=m%delmin2
k)==mhq2
whilehf(k,2)~=mhq2|hf(k,5)==1%findmin2location
k2=k;
hf(ki,2)=mhq1+mhq2;
hf(ki,3)=k1;
hf(ki,4)=k2;
hq=[hqhf(ki,2)];
clc
choose=input('
Pleasechoosewhatyouwant:
\n1:
Encoding\n2:
Decoding\n3:
.Exit\n'
whilechoose==1|choose==2
ifchoose==1
a=input('
PleaseinputtheletteryouwanttoEncoding:
whilehf(k,2