哈夫曼编码HuffmanCoding.docx

上传人:b****5 文档编号:6750622 上传时间:2023-01-10 格式:DOCX 页数:14 大小:18.92KB
下载 相关 举报
哈夫曼编码HuffmanCoding.docx_第1页
第1页 / 共14页
哈夫曼编码HuffmanCoding.docx_第2页
第2页 / 共14页
哈夫曼编码HuffmanCoding.docx_第3页
第3页 / 共14页
哈夫曼编码HuffmanCoding.docx_第4页
第4页 / 共14页
哈夫曼编码HuffmanCoding.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

哈夫曼编码HuffmanCoding.docx

《哈夫曼编码HuffmanCoding.docx》由会员分享,可在线阅读,更多相关《哈夫曼编码HuffmanCoding.docx(14页珍藏版)》请在冰豆网上搜索。

哈夫曼编码HuffmanCoding.docx

哈夫曼编码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

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

当前位置:首页 > 医药卫生 > 基础医学

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

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