赫夫曼樹-Huffman編碼
阿新 • • 發佈:2018-12-09
首先感嘆,Huffman真牛逼!!
儘量把檔案壓縮到最小
通過最優排序,大資料把人們最常用的字元放到樹前面,以實現最小編碼。
大致說一下原理,貼一下程式碼
1:使用者提供常用字元,建立一棵最優樹
2:得到每一個字元的編碼code
3:使用者輸入0和1,通過遍歷最優樹實現解碼
說起來很容易,編碼設計到佇列和二叉樹,確實不容易敲出來
接下來敲一下程式碼:/*注:沒使用標頭檔案,分檔案寫,考慮看家看的明白*/
/*還有就是頭節點應該和普通節點不一樣的,但是Debug時候出現不同struct型別不能賦值,所以乾脆使用同一個struct了,比較佔用空間,各位看官知道就行,當然可以優化*/
/* 輸入文字,建立佇列 生成huffman 樹 輸入編碼,輸出字元文字 */ #include <malloc.h> #include <iostream> using namespace std; typedef struct ht_node//huffman樹節點 { char data; struct ht_node *left,*right; }*TYPE; typedef struct quene_node//佇列節點 { TYPE val;//樹型別 unsigned int size; unsigned int priority;//優先順序 struct quene_node *next;//後繼 }*Q_node; typedef struct table_node { char symbol;//字元存放 char *code; struct table_node *next; }Table_node; typedef struct table { Table_node *first,*next; }*Table; void add_quene(Q_node &hufquene,TYPE &aux,unsigned int priority)//引數:佇列頭節點,樹節點,優先順序 { if(hufquene->size==256) { cout<<"Quene is full !!"; return; }//否則建立佇列節點 Q_node temp=(Q_node)malloc(sizeof(quene_node)); temp->priority=priority; temp->val=aux; ///////////////////////DEBUG///////////////////////////////// if(hufquene->size==0||hufquene->next==NULL)//只有頭節點 { //把元素插入佇列 temp->next=NULL; hufquene->next=temp; hufquene->size++; }else { //要進行比較後按順序優先順序從小到大排列 Q_node itertor=hufquene;//建立迭代節點,指向第一個節點 while(itertor->next!=NULL)//佇列中存在元素 { if(priority<=itertor->next->priority)//從第二個節點開始比較 { hufquene->size++; temp->next=itertor->next; itertor->next=temp;//頭插法 return; } itertor=itertor->next; } if(itertor->next==NULL) { temp->next=NULL; itertor->next=temp; hufquene->size++; return; } } } TYPE getquene(Q_node &hufquene) { TYPE returnvalue; if(hufquene->size>0) { Q_node tree_node= hufquene->next; returnvalue=tree_node->val; hufquene->next=tree_node->next; hufquene->size--; }else { cout<<"Empty!!"; } return returnvalue;//返回樹節點 } TYPE buildtree(char *inputstring) { int *probablity=(int *)malloc(sizeof(int)*256);//分配地址 for(int i=0;i<256;i++) probablity[i]=0;//初始化 for(int j=0;inputstring[j]!='\0';j++) { probablity[(inputstring[j])]++; }//統計字元出現次數 Q_node hufquene;//定義一個頭節點 //////初始化頭節點 hufquene=(Q_node)malloc(sizeof(quene_node)); hufquene->next=NULL; hufquene->size=0; /////////// //生成佇列 for(int k=0;k<256;k++) { if(probablity[k]!=0)//存在字元 { TYPE aux=(TYPE)malloc(sizeof(ht_node)); aux->data=(char)k; aux->left=NULL; aux->right=NULL;//為每一個字元分配一個樹節點 //插入佇列 add_quene(hufquene,aux,probablity[k]); } } //生成Huffman樹 while(hufquene->size!=1) { Q_node tyust=hufquene->next; unsigned int num=tyust->priority; num+=tyust->next->priority; TYPE left=getquene(hufquene); TYPE right=getquene(hufquene); TYPE huff_tree=(TYPE)malloc(sizeof(ht_node)); huff_tree->left=left; huff_tree->right=right; add_quene(hufquene,huff_tree,num);//再次插入 } TYPE root=(TYPE)malloc(sizeof(ht_node)); root=getquene(hufquene); return root; } void travertree(TYPE tree_node,Table &link,int k,char code[256]) { if(tree_node->left==NULL&&tree_node->right==NULL)//葉子 { code[k]='\0';//新增結束 Table_node *aux=(Table_node*)malloc(sizeof(Table_node)); aux->code=(char*)malloc(sizeof(char)*(strlen(code)+1)); strcpy(aux->code,code); aux->symbol=tree_node->data; aux->next=NULL; if(link->first==NULL) { link->first=link->next=aux; }else { link->next->next=aux; link->next=aux; } } if(tree_node->left!=NULL)//左子樹不為0 { code[k]='0'; travertree(tree_node->left,link,k+1,code); } if(tree_node->right!=NULL) { code[k]='1'; travertree(tree_node->right,link,k+1,code); } } Table build_table(TYPE tree_node)//建立 { Table tytable=(Table)malloc(sizeof(table)); tytable->first=NULL; tytable->next=NULL; char code[256]; int k=0; travertree(tree_node,tytable,k,code); return tytable; } void decode(TYPE root,char *str)//解碼 { TYPE temp=root; for(int i=0;str[i]!='\0';i++) { if(temp->left==NULL&&temp->right==NULL) { cout<<temp->data; temp=root;//碰到葉子後從根重新開始 } if(str[i]=='0') { temp=temp->left;//0向左走 } if(str[i]=='1') { temp=temp->right; } } } void main() { TYPE root=buildtree("Hello world I am CPP");//根據大資料生成最優樹 Table mark_table=build_table(root);//返回生成的最優排列 decode(root,"00011101111101");//還沒找到對應編碼多出的捨棄不要 cout<<endl; }