數(shù)據(jù)結(jié)構(gòu)和算法-哈夫曼編碼

一、概念

給定N個(gè)權(quán)值作為N個(gè)葉子結(jié)點(diǎn),構(gòu)造一棵二叉樹,若該樹的帶權(quán)路徑長度達(dá)到最小,稱這樣的二叉樹為最優(yōu)二叉樹,也稱為哈夫曼樹。哈夫曼樹是帶權(quán)路徑長度最短的樹,權(quán)值較大的結(jié)點(diǎn)離根較近

哈夫曼編碼(Huffman Coding),又稱霍夫曼編碼,是一種編碼方式,哈夫曼編碼是可變字長編碼(VLC)的一種。該方法完全依據(jù)字符出現(xiàn)概率來構(gòu)造異字頭的平均長度最短的碼字,有時(shí)稱之為最佳編碼,一般就叫做Huffman編碼(有時(shí)也稱為霍夫曼編碼)

二、構(gòu)建哈夫曼樹

由權(quán)值分別為5,15,40,30,10的字符ABCDE構(gòu)建哈夫曼樹
1、將權(quán)值最小的A,E作為樹的左右孩子,生成一棵樹,頂點(diǎn)為N1且權(quán)值為A和E的權(quán)值和15

BCA97988-F869-4C3B-A61C-1BD7F493FB49.png

2、繼續(xù)遍歷未加入到樹中的字符和樹的頂點(diǎn),將權(quán)值最小的兩個(gè)字符按左右孩子生成樹,頂點(diǎn)為N2,權(quán)值是左右孩子權(quán)值和

截屏2020-05-10下午10.23.07.png

截屏2020-05-10下午10.28.00.png

截屏2020-05-10下午10.31.04.png

代碼實(shí)現(xiàn)

const int MaxValue = 10000;//初始設(shè)定的權(quán)值最大值

//設(shè)定哈夫曼樹為順序存儲
//哈夫曼樹的結(jié)點(diǎn)結(jié)構(gòu)
typedef struct HuffNode{
  int weight;       //權(quán)值
  int flag;         //標(biāo)記是否已加入到樹中 0為沒加入,1為已加入
  int parent;       //該結(jié)點(diǎn)的雙親結(jié)點(diǎn)的下標(biāo)
  int leftChild;    //該結(jié)點(diǎn)的左孩子結(jié)點(diǎn)的下標(biāo)
  int rightChild;   //該結(jié)點(diǎn)的右孩子結(jié)點(diǎn)的下標(biāo)
}HuffNode;

構(gòu)建哈夫曼樹

void huffmanTree(int weight[], int n, HuffNode *h){
  //有n個(gè)葉子結(jié)點(diǎn)的樹共有2*n-1個(gè)結(jié)點(diǎn)
  for (int i = 0; i<2*n-1; i++) {
      if (i<n) {
          h[i].weight = weight[i];
      }else{
          h[i].weight = 0;
      }
      h[i].parent = 0;
      h[i].flag = 0;
      h[i].leftChild = -1;
      h[i].rightChild = -1;
  }
  int m1,m2,x1,x2;
  for (int i = 0; i<n-1; i++) {
      m1 = MaxValue;  //存儲權(quán)值最小的值
      m2 = MaxValue;  //存儲權(quán)值第二小的值
      x1 = 0;   //存儲權(quán)值最小的值的下標(biāo)
      x2 = 0;   //存儲權(quán)值第二小的值的下標(biāo)
      for (int j = 0; j<n+i; j++) {
          if (h[j].weight<m1 && h[j].flag == 0) {
              m2 = m1;
              x2 = x1;
              m1 = h[j].weight;
              x1 = j;
          }else if (h[j].weight<m2 && h[j].flag == 0){
              m2 = h[j].weight;
              x2 = j;
          }
      }
      h[x1].parent = n+i;
      h[x2].parent = n+i;
      h[x1].flag = 1;
      h[x2].flag = 1;
      
      h[n+i].leftChild = x1;
      h[n+i].rightChild = x2;
      h[n+i].weight = m1+m2;
  }
}

哈夫曼編碼

const int MaxBit = 8;//初始設(shè)定的最大編碼位數(shù)
typedef struct Code//存放哈夫曼編碼的數(shù)據(jù)元素結(jié)構(gòu)
{
  int bit[MaxBit];//數(shù)組
  int start;  //編碼的起始下標(biāo)
  int weight;//字符的權(quán)值
}Code;
void huffmanCode(HuffNode h[], int n, Code c[]){
  //創(chuàng)建一個(gè)結(jié)構(gòu)為Code的結(jié)點(diǎn)
  Code *cd = (Code *)malloc(sizeof(Code));
  int child, parent;
  
  //求n個(gè)葉子結(jié)點(diǎn)的哈夫曼編碼
  for (int i = 0; i<n; i++) {
      cd->start = 0;   //從0開始計(jì)數(shù)
      cd->weight = h[i].weight;  //獲取結(jié)點(diǎn)的權(quán)值
      child = i;
      parent = h[i].parent;
      
      //由葉結(jié)點(diǎn)向上到根結(jié)點(diǎn)
      while (parent != 0) {
          if (h[parent].leftChild == child) {
              cd->bit[cd->start] = 0;//該結(jié)點(diǎn)為左孩子編碼為0
          }else{
              cd->bit[cd->start] = 1;//該結(jié)點(diǎn)為右孩子編碼為1
          }
          cd->start++;
          child = parent;
          parent = h[child].parent;
      }
      //將編碼值反轉(zhuǎn)
      for (int j = cd->start - 1; j>=0; j--) {
          int k = cd->start - 1- j;
          c[i].bit[k] = cd->bit[j];
      }
      c[i].weight = cd->weight;
      c[i].start = cd->start;
  }
}

demo

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容