OK,昨天咱們對huffman數的基本知識,以及huffman樹的建立作了一些簡介,http://www.cnblogs.com/Frank-C/p/5017430.htmlhtml
今天接着聊:數組
huffman樹建立完成以後,咱們如何去獲得huffman編碼呢?編碼
圖12.4_1 huffman樹形結構spa
圖12.4_2 huffman存儲結構(數組)3d
首先,以上面的樹爲例,咱們必須明白幾個要點: 指針
1:從什麼地方開始訪問這顆樹:根節點 , index 2n-1 = 15code
2:訪問的規則:向左爲0 向右爲1htm
3:以什麼樣的訪問循序去訪問呢?blog
好說,get
(1): 詢問是否有左孩子,一直向左走,直到左孩子爲零,若是此時右孩子也爲零,證實已經找到了一個葉子結點(信息元)。(固然,在訪問的同時進行編碼記錄)
(2): 原路返回一層(編碼同時減一),詢問是否有右孩子,有,進入右孩子,無,再返回上一層
一直重複(1)和(2)步,直到最終回退到更節點,在回到根節點的parent,即此時迭代器(index)爲零
固然,我只是說了一下大概的步驟,具體的代碼實現,還得是細之又細,往下看!!!!!! 有木有
*HC=(HuffmanCode)malloc((n+1)*sizeof(char*)); /* 分配n個字符編碼的頭指針向量([0]不用) */ cd=(char*)malloc(n*sizeof(char)); /* 分配求編碼的工做空間 即傳遞(temp)空間*/ c=m; //直接指向最上面那個非葉子節點 cdlen=0; for(i=1;i<=m;++i)/* 遍歷赫夫曼樹時用做結點狀態標誌 直接把所有節點置爲零 此時這棵樹已經創建了 故權重已經沒有多大用處了*/ (*HT)[i].weight=0; while(c) { if((*HT)[c].weight==0) //負責向左 { /* 向左 */ (*HT)[c].weight=1; /* ************* */ if((*HT)[c].lchild!=0) /*若是權爲零的左孩子節點不是第一個元素(下標爲0)*/ { c=(*HT)[c].lchild; cd[cdlen++]='0'; } /*看這個左孩子有沒有右孩子 若是右孩子爲零(即沒有右孩子),那麼是一個葉子節點*/ else if((*HT)[c].rchild==0) { /* 登記葉子結點的字符的編碼 */ (*HC)[c]=(char *)malloc((cdlen+1)*sizeof(char)); cd[cdlen]='\0'; strcpy((*HC)[c],cd); /* 複製編碼(串) */ } } /*條件改變*/ else if((*HT)[c].weight==1) /*負責向右 只會回退 不會動 判斷是左孩子是葉子節點仍是中間的內點*/ { /* 向右 */ (*HT)[c].weight=2; /////************ if((*HT)[c].rchild!=0) //決定你這個權值此時會不會被清零 { c=(*HT)[c].rchild; cd[cdlen++]='1'; } } else //負責回退 { /* HT[c].weight==2,退回 */ (*HT)[c].weight=0; /////************** c=(*HT)[c].parent; --cdlen; /* 退到父結點,編碼長度減1 迭代:利用前面走過的路*/ } } free(cd);
上面代碼經過一個weight(在while語句執行以前就已經被清零了哦哦哦),來判斷當前節點(葉子節點的狀況除外):(只做爲過程說明,不是狀態判斷條件)
未被訪問或已經被訪問且沒有用了: 0
正在訪問左樹且「右樹尚未訪問」(固然這是廢話): 1
正在訪問右樹且 」左樹已經訪問「 (固然這也是廢話): 2
何時回退,左節點沒有或已經訪問完,且,右節點沒有或已經訪問玩,如何保證以前這些個條件呢。簡單,if else分支語句的做用體現出來了,把負責回退的判斷語句放在最後,前面來判斷有左孩子木有哈,有右孩子木有啊,沒有,證實找到一個葉子節點(信息元),記錄信息,此時,此葉子節點weight已經被置爲1,那麼最中被置爲2且沒有右節點,進入最後一個else分支,置爲零且回退。
當分支節點爲1是(此時左節點已經被訪問),會首先被置爲2,詢問是否有右節點,有進入,即注意,當前節點若是是父節點的右孩子,字此時的父節點weight定被置爲了二,當此節點爲葉子節點且符合上面的葉子節點回退規則時,回退到父節點,父節點有爲2,繼續回退。
總結:代碼分支語句分紅了三個主分支塊 weight爲0(判斷是否未訪問過的節點) weight爲1(判斷是否爲左樹已經訪問) weight爲2,節點weight須要進行清零且回退
對於葉子節點,則主要有第一個分支塊進行處理,並由第二和三個分支塊進行輔助判斷與回退。
如何去經過編碼反編譯成信息或信息元,我想着就再簡單不過了,至少比編碼的建立容易吧,直接根據樹以必定的規則去找(如,0:左孩子, 1:右孩子), 鑑於每一個信息元的獨立性與信息元之間的無包含性,既適合反編碼,有適合找錯誤。
OK,That’s all!!!