哈夫曼编码HuffmanCoding.docx
- 文档编号:6750622
- 上传时间:2023-01-10
- 格式:DOCX
- 页数:14
- 大小:18.92KB
哈夫曼编码HuffmanCoding.docx
《哈夫曼编码HuffmanCoding.docx》由会员分享,可在线阅读,更多相关《哈夫曼编码HuffmanCoding.docx(14页珍藏版)》请在冰豆网上搜索。
哈夫曼编码HuffmanCoding
哈夫曼编码
哈夫曼编码(HuffmanCoding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。
Huffman于1952年提出一种编码方式,该方式完全依据字符显现概率来构造异字头的平均长度最短的码字,有时称之为最正确编码,一样就叫作Huffman编码。
以─即最优二叉树,带权途径长度最小的二叉树,常常应用于数据紧缩。
在运算机信息处置中,“哈夫曼编码”是一种一致性编码法(又称"熵编码法"),用于数据的无损耗紧缩。
这一术语是指利用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。
这张编码表的特殊的地方在于,它是依照每一个源字符显现的估算概率而成立起来的(显现概率高的字符利用较短的编码,反之显现概率低的那么利用较长的编码,这便使编码以后的字符串的平均期望长度降低,从而达到无损紧缩数据的目的)。
这种方式是由进展起来的。
例如,在英文中,e的显现概率很高,而z的显现概率那么最低。
当利用哈夫曼编码对一篇英文进行紧缩时,e极有可能用一个位(bit)来表示,而z那么可能花去25个位(不是26)。
用一般的表示方式时,每一个英文字母均占用一个字节(byte),即8个位。
二者相较,e利用了一样编码的1/8的长度,z那么利用了3倍多。
倘假设咱们能实现关于英文中各个字母显现概率的较准确的估算,就能够够大幅度提高无损紧缩的比例。
本文描述在网上能够找到的最简单,最快速的哈夫曼编码。
本方式不利用任何扩展动态库,比如STL或组件。
只利用简单的C函数,比如:
memset,memmove,qsort,malloc,realloc和memcpy。
因此,大伙儿都会发觉,明白得乃至修改那个编码都是很容易的。
背景
哈夫曼紧缩是个无损的紧缩算法,一样用来紧缩文本和程序文件。
哈夫曼紧缩属于可变代码长度算法一族。
意思是个体符号(例如,文本文件中的字符)用一个特定长度的位序列替代。
因此,在文件中显现频率高的符号,利用短的位序列,而那些很少显现的符号,那么用较长的位序列。
编码利用
我用简单的C函数写那个编码是为了让它在任何地址利用都会比较方便。
你能够将他们放到类中,或直接利用那个函数。
而且我利用了简单的格式,仅仅输入输出缓冲区,而不象其它文章中那样,输入输出文件。
boolCompressHuffman(BYTE*pSrc,intnSrcLen,BYTE*&pDes,int&nDesLen);
boolDecompressHuffman(BYTE*pSrc,intnSrcLen,BYTE*&pDes,int&nDesLen);
要点说明
速度
为了让它快速运行,我花了很长时刻。
同时,我没有利用任何动态库,比如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); 构造哈夫曼树超级简单,将所有的节点放到一个队列中,用一个节点替换两个频率最低的节点,新节点的频率确实是这两个节点的频率之和。 如此,新节点确实是两个被替换节点的父节点了。 如此循环,直到队列中只剩一个节点(树根)。 wCode<<(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<> #include<> #defineM10 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; } elseprintf("Error! "); } h) { 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 { w=; =FN[max].weight; FN[max].weight=w; c=; =FN[max].ch; FN[max].ch=c; } } for(i=1;i<=n;i++)/*初始化h*/ h=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[h]='0'; h++; } if(sta! =m) EnterQueue(Q,sta,m); else fc[sta][h[sta]]='\0'; for(i=m+1;i<=end;i++) { fc[h]='1'; h++; } if(m==sta&&(m+1)==end)=ch; (*CW)[*p].weight=1; for(k=i+1;ch[k]! ='\0';k++) if(ch==ch[k]) (*CW)[*p].weight++; } } *s=i; } /********创建HuffmanTree********/ voidCreateHuffmanTree(Huffman*ht,WeightNodew,intn) { inti,j; ints1,s2; for(i=1;i<=n;i++) { (*ht).weight=; (*ht).parent=0; (*ht).LChild=0; (*ht).RChild=0; } for(i=n+1;i<=2*n-1;i++) { (*ht).weight=0; (*ht).parent=0; (*ht).LChild=0; (*ht).parent=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).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).RChild=s2; (*ht).weight=(*ht)[s1].weight+(*ht)[s2].weight; } } /***********叶子结点的编码***********/ voidCrtHuffmanNodeCode(Huffmanht,charch[],HuffmanCode*h,WeightNode*weight,intm,intn) { inti,j,k,c,p,start; char*cd; cd=(char*)malloc(n*sizeof(char)); cd[n-1]='\0'; for(i=1;i<=n;i++) { start=n-1; c=i; p=; while(p) { start--; if(ht[p].LChild==c) cd[start]='0'; else cd[start]='1'; c=p; p=ht[p].parent; } (*weight).num=n-start; (*h)=(char*)malloc((n-start)*sizeof(char)); p=-1; strcpy((*h),&cd[start]); } system("pause"); } /*********所有字符的编码*********/ voidCrtHuffmanCode(charch[],HuffmanCodeh,HuffmanCode*hc,WeightNodeweight,intn,intm) { inti,j,k; for(i=0;i { for(k=1;k<=n;k++)/*从(*weight)[k].c中查找与ch相等的下标K*/ if(ch==weight[k].c) break; (*hc)=(char*)malloc((weight[k].num+1)*sizeof(char)); for(j=0;j<=weight[k].num;j++) (*hc)[j]=h[k][j]; } } /*****解码*****/ voidTrsHuffmanTree(Huffmanht,WeightNodew,HuffmanCodehc,intn,intm) { inti=0,j,p; printf("***StringInformation***\n"); while(i { p=2*n-1; for(j=0;hc[j]! ='\0';j++) { if(hc[j]=='0') p=ht[p].LChild; else p=ht[p].RChild; } printf("%c",w[p].c);/*打印原信息*/ i++; } } main() { inti,n,m,s1,s2,j;/*n为叶子结点的个数*/ charch[N],w[N];/*ch[N]寄存输入的字符串*/ Huffmanht;/*二叉数*/ 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",; printf("\nWeight"); for(i=1;i<=n;i++) printf("%d",; CreateHuffmanTree(&ht,weight,n);/*产生Huffman树*/ printf("\n***HuffamnTreeInformation***\n"); for(i=1;i<=2*n-1;i++)/*打印Huffman树的信息*/ printf("\t%d%d%d%d\n",i,,,,; CrtHuffmanNodeCode(ht,ch,&h,&weight,m,n);/*叶子结点的编码*/ printf("***NodeCode***\n");/*打印叶子结点的编码*/ for(i=1;i<=n;i++) { printf("\t%c: ",; printf("%s\n",h); } CrtHuffmanCode(ch,h,&hc,weight,n,m);/*所有字符的编码*/ printf("***StringCode***\n");/*打印字符串的编码*/ for(i=0;i printf("%s",hc); system("pause"); TrsHuffmanTree(ht,weight,hc,n,m);/*解码*/ system("pause"); } 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)~=a k=k+1; ifk>=n display('Error! Youdidnotinputthisnumber.'); break end end ifk>=n break end r=[]; whilehf(k,5)==1 kc=n+1; whilehf(kc,3)~=k&hf(kc,4)~=k kc=kc+1; end ifhf(kc,3)==k r=[0r]; else r=[1r]; end k=kc; end r else a=input('PleaseinputthemetrixyouwanttoDecoding: '); sa=size(a); sa=sa(: 2); k=2*n-1; whilesa~=0 ifa(: 1)==0 k=hf(k,3); else k=hf(k,4); end a=a(: 2: sa); sa=sa-1; ifk==0 display('Error! Themetrixyouenteredisawrongone.'); break end end ifk==0 break end r=hf(k,2); r end choose=input('Pleasechoosewhatyouwant: \n1: Encoding\n2: Decoding\n3: .Exit\n'); clc end ifchoose~=1&choose~=2 clc; end
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 哈夫曼 编码 HuffmanCoding
![提示](https://static.bdocx.com/images/bang_tan.gif)