數據結構之Huffman樹與最優二叉樹

  最近在翻炒一些關於樹的知識,發現一個比較有意思的二叉樹,huffman樹,對應到離散數學中的一種名爲最優二叉樹的路徑結構,而Huffman的主要做用,最終能夠歸結到一種名爲huffman編碼的編碼方式,使用huffman編碼方式,咱們能夠以平均長度最短的碼字來記錄一串信息,且每一個信息分子的編碼惟一,獨立。從而最終合成編碼所對應的信息惟一,無歧義。數組

huffman樹的建立時基於每一個信息分子都擁有其權重,權重越大,越靠近樹根,即路徑越短,數據結構

下面咱們咱們來以一個huffman樹的例子爲例:簡單引入一下huffman樹:編碼

image

  上圖便是構造huffman編碼所必備的元素,那麼,經過上圖中的信息分子與對應編碼,咱們就能夠寫出編碼解析結果惟一且無歧義的編碼串  如: spa

            001011110100111     CDGFHcode

            000111110010          CHEFblog

 

huffman編碼的任何組合方式都只可能對應一串信息,不可能有歧義出現。 由於在huffman樹中,每個信息元都是一個葉子節點。。。get

 

期huffman樹形結果爲:數學

image

  圓圈中的數字表示權重,咱們規定向左爲0   向右爲1 ,, 即的到上面表格中的huffman編碼,經過上圖中的樹,咱們不難算出樹的權it

W(T)爲291651   必爲全部的由這些信息元組合成的樹中的權的最小值,固然,組合方式有可能不同,但最終的權,只會大於或等於他,即不存在與權值相等且爲最小權值的非同構的兩顆樹。class

 

如何建立這個huffman樹(最優二叉樹)呢,這纔是咱們今天的關鍵。

  首先咱們須要明確同樣東西,基於信息元所建立的huffman樹的節點個數是否肯定,答案是確定的,若是在一開始咱們所要建立的數據結構的長度是肯定的話,那麼我以爲咱們有很大的必要選擇數組了。

  數組的長度:m = 信息元個數n * 2 - 1;   即咱們須要n個單元存放信息元節點,n-1的單元來存放分支點(內點和根節點)。

  數組單元的數據結構(不考慮信息元數據):

               image

  因爲樹的存儲結構是用數組實現的,故parent,rchild,lchild中直接保存數組下標便可。

一切都具有好了,那哥們兒幾個就來初始化一下這棵樹把(以上面的例子爲例):

(初始狀態,還未進行建樹):

image

 

建樹動做完成以後:

image

咦,中間的步驟哪裏去了呢???   別急!!!

  聽我說:  1:尋找數組中單元數據的parent不爲零的兩個數組元c1 , c2

                2:找到他們的父節點father,父節點:數組index遞增序列中第一個weight爲零的數組元(前提:信息元中不存在weight爲零的權)。

                3:將父節點的lchild指向c1 和 c2中序號(index)在前面的那個數組單元(即lchild = indexMin(c1,c2).index), rchild則等於另外一個的index,將c1和c2的parent都指向找到的父節點,即c1/c2.parent = father.index。同時c1和c2的權之和賦給father的weight(權)

                4:重複1,2,3,直到左右數組單元的weight都被數據化(賦值)。

代碼以下:

void HuffmanCoding(HuffmanTree *HT,int *w,int n)
{  /*w爲權值數組,n爲信息元個數*/
   int m,i,s1,s2; 
   HuffmanTree p;
   char *cd;
   if(n<=1)
     return;
   m=2*n-1;
   *HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); /* 0號單元未用 */
   for(p=*HT+1,i=1;i<=n;++i,++p,++w)    //parent lcahid rchild所有初始化爲零
   {
     (*p).weight=*w;
     (*p).parent=0;
     (*p).lchild=0;
     (*p).rchild=0;
   }
   for(;i<=m;++i,++p)
     (*p).parent=0;
   for(i=n+1;i<=m;++i) /* 建赫夫曼樹 */ 
   { /* 在HT[1~i-1]中選擇parent爲0且weight最小的兩個結點,其序號分別爲s1和s2 */
     select(*HT,i-1,&s1,&s2);
     (*HT)[s1].parent=(*HT)[s2].parent=i;
     (*HT)[i].lchild=s1;
     (*HT)[i].rchild=s2;
     (*HT)[i].weight=(*HT)[s1].weight+(*HT)[s2].weight;
   }
}

          那麼,最終的huffman編碼如何實現,以及咱們如何起實現反編碼(從編碼獲得信息),筆者將會最從此的日子裏進行探討(沒時間啦啦),阿里亞瑟哦,以爲不錯的話,記得點贊哦。

相關文章
相關標籤/搜索