霍夫曼编码总结

霍夫曼编码总结

作者:CC  Time:2010-1-9

霍夫曼(Huffman)编码是1952年为文本文件而建立,是一种统计编码。属于无损压缩编码。

霍夫曼编码的码长是变化的,对于出现频率高的信息,编码的长度较短;而对于出现频率低的信息,编码长度较长。这样,处理全部信息的总码长一定小于实际信息的符号长度。

霍夫曼计算法步骤进行:

l)将信号源的符号按照出现概率递减的顺序排列。   

2)将两个最小出现概率进行合并相加,得到的结果作为新符号的出现概率。   

3)重复进行步骤12直到概率相加的结果等于1为止。   

4)在合并运算时,概率大的符号用编码0表示,概率小的符号用编码1表示。   

5)记录下概率为1处到当前信号源符号之间的0l序列,从而得到每个符号的编码。

霍夫曼计算法举例:

霍夫曼优点:

霍夫曼码的码长虽然是可变的,但却自带同步代码。例如,码串中的第1位为0,那末肯定是符号A,因为表示其他符号的代码没有一个是以0开始的,因此下一位就表示下一个符号代码的第1位。同样,如果出现“110”,那么它就代表符号D。如果事先编写出一本解释各种代码意义的“词典”,即码簿,那么就可以根据码簿一个码一个码地依次进行译码。

霍夫曼编码方法的编码效率比香农-范诺编码效率高一些

霍夫曼缺点:

     霍夫曼码没有错误保护功能,在译码时,如果码串中没有错误,那么就能一个接一个地正确译出代码。但如果码串中有错误,哪仅是1位出现错误,不但这个码本身译错,更糟糕的是一错一大串,全乱了套,这种现象称为错误传播(error propagation)。计算机对这种错误也无能为力,说不出错在哪里,更谈不上去纠正它。

     霍夫曼码是可变长度码,因此很难随意查找或调用压缩文件中间的内容,然后再译码,这就需要在存储代码之前加以考虑。硬件实现有难度。

     由于"0""1"的指定是任意的,故由上述过程编出的最佳码不是唯一的,但其平均码长是一样的,故不影响编码效率与数据压缩性能。

     压缩与还原相当费时。

     对不同信号源的编码效率不同

 

霍夫曼C语言实现:

#includestdio.h>
#includestdlib.h>
#includestring.h>
#includemalloc.h>
#define N 20
#define M 2*N-1
#define Min 1000 /*
最小值
*/
typedef struct
{
  char ch; /*
权值对应的字符
*/
  int weight; /*
权值
*/
  int parent; /*
双亲位置
*/
  int Lchild; /*
左孩子位置
*/
  int Rchild; /*
右孩子位置
*/
}HTNode,Huffmantree[M+1];
char hc[N+1][N+1];
void OutputHuffmancode(Huffmantree ht, int n);
void CrtHuffmancode(Huffmantree ht, int n);
void OutputHuffmantree(Huffmantree ht,int n);
void select(Huffmantree ht,int a,int *s1,int *s2)
{
  int i;
  int c1=Min;
  int c2;
  for(i=1;i=a;i++)
   {
    if (ht
.parent==0&&ht.weightc1)
     {
       *s1=i;
       c1=ht.weight;
      }
    }
  c2=Min;
  for(i=1;i=a;i++)
   {
    if (ht.parent==0&&(*s1!=i)&&c2>ht.weight)
     {
       *s2=i;
       c2=ht.weight;
      }
    }
}
void CrtHuffmantree(Huffmantree ht,int w[],char elem[],int n)
{
  int i;
  int m;
  int s1,s2;
  m=2*n-1;
  
  ht=(HTNode *)malloc((m)*sizeof(HTNode));
  
  for(i=1;i=n;i++)
   {
    ht.ch=elem[i-1];
    ht.weight=w[i-1];
    ht.parent=0;
    ht.Lchild=0;
    ht.Rchild=0;
   }
  for(i=n+1;i=m;i++)
   {
    ht.ch='/0';
    ht.weight=0;
    ht.parent=0;
    ht.Lchild=0;
    ht.Rchild=0;
   }
  /*
初始化完毕*/
  for(i=n+1;i=m;i++)
  {
    select( ht,i-1,&s1,&s2); /*
返回最小值和次小值的位置
*/
    ht.weight=ht[s1].weight+ht[s2].weight;
    ht[s1].parent=i;
    ht[s2].parent=i;
    ht.Lchild=s1;
    ht.Rchild=s2;/*
建立树完毕
*/
  }
   OutputHuffmantree( ht,m);
   printf("now begin crthuffman code/n");
   CrtHuffmancode( ht, n);
   printf("crthuffman code end/n");
   OutputHuffmancode(ht, n);
}
void OutputHuffmantree(Huffmantree ht,int n)
{
   int i;
   printf("/nnumber---weight---parent---Lchild---Rchild---huffman char/n /n");
   for(i=1;i=n;i++)
     printf("%d/t%d/t%d/t%d/t%d/t%c/n",i,ht.weight,ht.parent,ht.Lchild,ht.Rchild,ht.ch);
}
void CrtHuffmancode(Huffmantree ht, int n) /*
建立编码
*/
{
     int i,c,p;
     int start;
     char *cd;
     cd=(char *) malloc((n+1)*sizeof(char));
     memset(cd,'/0',sizeof(cd));
     
     for(i=1;i=n;i++)
     {
        start=n;
        cd[start]='/0';
        
        c=i;
        p=ht.parent;
        while(p!=0)
         {
           start--;
           if(ht[p].Lchild==c)
             cd[start]='0';
           else
              cd[start]='1';
           
            c=p;
            p=ht[p].parent;
         }
      //cd[start] = '/0';
      printf("cd is %s/n start is %d/n", cd+start, start);
       sprintf(hc, "%s", cd+start); /*
将已存在的编码复制到code
*/
      }
     free(cd);
}
void OutputHuffmancode(Huffmantree ht,int n)
{
  int i;
  printf("/nweight_char---weight---huffmancode/n /n");
  for(i=1;i=n;i++)
    printf(" %c/t%4d/t%s/n",ht.ch,ht.weight,hc);
}
int main()
{
  int n = 6;/*
记录了权值个数
*/
  Huffmantree hfm;

  int w[] = {45,13,12,16,9,5};
  char elem[] = {'a','b','c','d','e','f'};
  
  CrtHuffmantree( hfm, w,elem, n);
  return 0;
}

 

霍夫曼C++语言实现:

//以下為C++程式碼,在GCC下編譯通過
//僅用於示範如何根據權值構建霍夫曼樹,沒有經過性能上的優化及加上完善的異常處理。
#include <cstdlib>
#include <iostream>
#include <deque>
#include <algorithm>
 
using namespace std;
 
const int size=10;
struct node                                 //霍夫曼樹節點結構
{
    unsigned key;                           //保存權值
    node* lchild;                           //左孩子指針
    node* rchild;                           //右孩子指針
};
deque<node*> forest;
deque<bool> code;                           //此處也可使用bitset
node* ptr;                   
int frequency[size]={0};
 
void printCode(deque<bool> ptr);            //用於輸出霍夫曼編碼
int main(int argc, char *argv[])
{
    for (int i=0;i<size;i++)
    {
        cin>>frequency[i];                  //輸入10個權值
        ptr=new node;
        ptr->key=frequency[i];
        ptr->lchild=NULL;
        ptr->rchild=NULL;
        forest.push_back(ptr);
    }//形成森林,森林中的每一棵樹都是一個節點
 
    //從森林構建霍夫曼樹
    for (int i=0;i<size-1;i++)
    {
               sort(forest.begin(),forest.end(),compare);
               ptr=new node;
                //以下代碼使用下標索引隊列元素,具有潛在危險,使用時請注意
               ptr->key=forest[0]->key+forest[1]->key;
               ptr->lchild=forest[0];
               ptr->rchild=forest[1];
               forest.pop_front();
               forest.pop_front();
               forest.push_back(ptr);
        }
    ptr=forest.front();//ptr是一個指向根的指針
    system("PAUSE");
    return EXIT_SUCCESS;
}
 
void printCode(deque<bool> ptr)
{
        //deque<bool>
        for (int i=0;i<ptr.size();i++)
        {
               if(ptr[i])
                       cout<<"1";
               else
                       cout<<"0";
        }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值