對26個英文字母進行huffman編碼
阿新 • • 發佈:2019-02-08
<ol><li class="alt"><span><span class="comment">1、建立哈夫曼樹</span> </span></li><li><span><span class="comment">2、從每個葉結點回溯到root的路徑,並記錄路徑,則為哈夫曼編碼</span> </span></li><li class="alt"><span><span class="comment">3、查表方式獲得每個字元的哈夫曼編碼</span> </span></li></ol>
#include <stdio.h> #include <stdlib.h> #include <string.h> ///----------------------定義結點資料--------------- #define leave 26 #define node (26*2-1) typedef struct nodee { char character; float weight; int lson; int rson; int par; }Node,*pnode; typedef struct code { int hufcode[leave];///葉節點最長編碼位數應該為樹的最長路徑 ,儲存編碼結果 int sta; ///編碼起始位(相對編碼陣列) char Char; ///編碼的字元值 }Code,*pcode; ///----------------------構造哈夫曼樹---------------- void huffman(Node ht[],float wt[]) { int i,j,x1,x2; float min1,min2; ///初始化結點陣列ht ,即對huffman樹進行初始化 for(i=0;i<node;i++) { ht[i].par=-1; ht[i].lson=-1; ht[i].rson=-1; if(i<leave) { ht[i].weight=wt[i]; ht[i].character=i+65;///A-Z的ASCii碼 } else { ht[i].weight=0; ht[i].character='?';///生成的中間結點字元值標記為'?' } } ///控制n-1次結點的結合(若有n個葉結點) for(i=1;i<leave;i++) { min1=min2=100;///min1、min2記錄當前最小、次小權值 x1=x2=0; ///x1、x2記錄當前最小次小權值結點的位置(陣列標號) for(j=0;j<leave-1+i;j++) ///在[0-j]範圍內找最小次小權值結點 { if(ht[j].par==-1 && ht[j].weight<min1)///parent元素的判斷是為了排除已結合過的結點,結合過的結點parent有正值 { min2=min1;///當前結點權值小於最小值,所以當前結點變成最小權值結點,原最小結點變成原來的次小結點 x2=x1; min1=ht[j].weight; x1=j; } else { if(ht[j].par==-1 && ht[j].weight<min2) ///當前結點權值大於最小值,小於次小值,則取代次小結點 { min2=ht[j].weight; x2=j; } } } ///將找到的最小、次小權值結點結合成樹,為其父結點賦值,可見該哈夫曼樹的根節點應該是ht陣列最後一個結點ht[node-1] ht[x1].par=leave-1+i; ht[x2].par=leave-1+i; ht[leave-1+i].weight=ht[x1].weight+ht[x2].weight; ht[leave-1+i].lson=x1; ht[leave-1+i].rson=x2; } } ///--------------------獲取並儲存每個葉節點的哈夫曼編碼供解碼時查詢-------------------------- void codeht(Node ht[],Code hc[]) { int i,j,d,p; Code x; ///依次每個葉結點(在哈夫曼結點陣列的最前面的空間中)尋找雙親直到root,記錄路徑,路徑就是哈夫曼編碼 for(i=0;i<leave;i++)///從每個字母都向上找尋根節點,使得整個樹完整的編碼 { x.Char=ht[i].character; x.sta=leave-1;///預設編碼起點為編碼陣列最後一位 d=i; p=ht[i].par; while(1) { if(ht[p].lson == d) x.hufcode[x.sta]=0;///預設編碼為左0右1 else if(ht[p].rson==d) x.hufcode[x.sta]=1; else printf("ERROR!!"); d=p; p=ht[d].par;///繼續向著根延伸編碼 if(p==-1)break;///到了26個字母以外停止,ht[i]為root結點退出迴圈,說明已經回溯到了根結點 x.sta--; } for(j=x.sta;j<leave;j++) { hc[i].hufcode[j]=x.hufcode[j]; } hc[i].sta=x.sta; hc[i].Char=x.Char; } } ///--------------------輸出每個字元的的哈夫曼編碼------------------------ void printcode(Code hc[]) { int i,j; for(i=0;i<leave;i++) { printf("字母%c的huffman編碼為:",hc[i].Char); for(j=hc[i].sta;j<leave;j++) { printf("%d",hc[i].hufcode[j]); } printf("\n"); } } ///-----------------------查詢字元的編碼--------------------------- void findcode(Code hc[]) { int i,j; char x; printf("請輸入一個大寫英文字母:"); while(scanf("%c",&x)!=EOF) { getchar(); for(i=0;i<leave;i++) { if(x==hc[i].Char) { printf("字元%c的huffman編碼為:",x); for(j=hc[i].sta;j<leave;j++) { printf("%d",hc[i].hufcode[j]); } printf("\n"); } } printf("請輸入一個大寫英文字母:"); } } ///---------------------主函式----------------------- int main() { Node huftree[node];///存放所有結點資料 Code hcode[leave];///存放所有的編碼結果 ///存放葉結點權值 float wt[leave]={0.0856,0.0139,0.0297,0.0378,0.1304,0.0289,0.0199,0.0528,0.0627,0.0013,0.0042,0.0339,0.0249,0.0707,0.0797,0.0199,0.0012,0.0677,0.0607,0.1045,0.0249,0.0092,0.0149,0.0017,0.0199,0.0008}; huffman(huftree,wt); codeht(huftree,hcode); printcode(hcode);///呼叫可以輸出所有的字母編碼 findcode(hcode); return 0; }