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


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

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

下面我們我們來以一個huffman樹的例子為例:簡單引入一下huffman樹:

image

  上圖即是構造huffman編碼所必備的元素,那么,通過上圖中的信息分子與對應編碼,我們就可以寫出編碼解析結果唯一且無歧義的編碼串  如: 

            001011110100111     CDGFH

            000111110010          CHEF

 

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

 

期huffman樹形結果為:

image

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

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

 

如何創建這個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編碼如何實現,以及我們如何起實現反編碼(從編碼得到信息),筆者將會最今后的日子里進行探討(沒時間啦啦),阿里亞瑟哦,覺得不錯的話,記得點贊哦。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM