赫夫曼樹編碼解碼實例(C)
阿新 • • 發佈:2017-11-17
sta nod 輸入 sign 赫夫曼 spa 字符數組 ++ es2017
//HuffmanTree.h #include <stdlib.h> #include <stdio.h> #include <string.h> #define OVERFLOW -1 typedef struct{ char data; //節點所存字符 unsigned int weight; //節點權重 unsigned int parent,lchild,rchild; }HTNode, *HuffmanTree; //動態分配數組存儲赫夫曼樹 typedef char** HuffmanCode;//動態分配數組存儲赫夫曼編碼表 //從T的1到n個節點中找出沒有結合(即parent=0)的節點中權重weight最小的兩個節點的下標;用l,r帶回; void Select(HuffmanTree T,int n,int&l,int&r) { HuffmanTree p=T+1;int a=0,b=0; for(int i=1;i<=n;++i,++p){ if(!p->parent){//找出雙親節點為空的節點; if(!a){l=i;a=1;} else if(!b){r=i;b=1;}else if(p->weight<(T+l)->weight||p->weight<(T+r)->weight){ if((T+l)->weight<=(T+r)->weight)r=i; else l=i; } } } } //w存放n個字符的權值(均>0),構造赫夫曼樹HT,並求出n個字符的赫夫曼編碼HC //HT為赫夫曼樹,HC為赫夫曼編碼,w為權重數組,n為w長度 void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int*w, char* c, int n){ if(n<=1) return; int m = 2*n-1; HT = (HuffmanTree)malloc((m+1)*sizeof(HTNode)); //0號單元未用 HuffmanTree p; int i; for(p=HT+1,i=1; i<=n; ++i,++p,++w) *p = {c[i-1],*w,0,0,0}; for(i=n+1; i<=m; ++i, ++p) *p = {0,0,0,0,0}; for(i=n+1; i<=m; ++i){ //建赫夫曼樹 //在HT[1..i-1]選擇parent為0且weight最小的兩個節點,其序號分別為s1和s2。 int s1,s2; Select(HT, i-1, s1, s2); HT[s1].parent = i; HT[s2].parent = i; HT[i].lchild = s1; HT[i].rchild = s2; HT[i].weight = HT[s1].weight + HT[s2].weight; } //---從葉子到根逆向求每個字符的赫夫曼編碼--- HC = (HuffmanCode)malloc((n+1)*sizeof(char *)); //分配n個字符編碼的頭指針向量 char* cd = (char *)malloc(n*sizeof(char)); //分配求編碼的工作空間 cd[n-1] = ‘\0‘; //編碼結束符 for(i=1; i<=n; ++i){ //逐個字符求赫夫曼編碼 int start = n-1; //編碼結束符位置 int c,f; for(c=i, f=HT[i].parent; f!=0; c=f,f=HT[f].parent) //從葉子到根逆向求編碼 if(HT[f].lchild == c) cd[--start] = ‘0‘; else cd[--start] = ‘1‘; HC[i] = (char *)malloc((n-start)*sizeof(char)); //為第i個字符編碼分配空間 strcpy(HC[i],&cd[start]); //從cd復制編碼(串)到HC } free(cd); //釋放工作空間 } //輸出赫夫曼編碼 //HC為赫夫曼編碼,w為權重數組,n為w長度,c為字符數組 void PrintHuffmanCode(HuffmanCode HC,int* w,char* c,int n) { char *p; int i; for(i=1;i<=n;++i){ printf("字符:%c,權重:%3d,編碼:", c[i-1], w[i-1]); p=HC[i]; printf("%s\n",p); } } //返回某字符的赫夫曼編碼 //HC為赫夫曼編碼,c為字符數組,n為c長度,ch為要編碼的字符 char* EnCode(HuffmanCode HC, char* c, char ch, int n) { int i; for(i=0;i<n;++i){ if(c[i]==ch){ char *p = HC[i+1]; return p; } } } //解碼 //s為待解碼字符串,HT為赫夫曼樹 char* DeCode(const char*s, HuffmanTree HT){ int i; HuffmanTree p=HT; static char result[500]; int j=0; //尋找根節點 while(p->parent!=0) p++; const HuffmanTree root = p; for(i=0; i<strlen(s); ++i){ if(s[i]==‘0‘){ if(p->lchild!=0){ p=HT+p->lchild; } } else if(s[i]==‘1‘){ if(p->rchild!=0){ p=HT+p->rchild; } } if(p->lchild==0&&p->rchild==0){ result[j]=p->data;++j; p = root; } } result[j] = ‘\0‘; return result; }
#include "HuffmanTree.h" #include <stdio.h> int main(void){ char s[500]; READ: printf("請輸入一段話:"); gets(s); int i=0,w[1000]={0},*word; char *c; //word記錄權值,c記錄字符 while(s[i]!=‘\0‘){ //出現次數計數 w[s[i]+500]++; ++i; } int j=0; word = (int*)malloc(sizeof(int)); c = (char*)malloc(sizeof(char)); for(i=-500;i<500;++i){ if(w[i+500]!=0){ word = (int*)realloc(word,(j+1)*sizeof(int)); c = (char*)realloc(c,(j+1)*sizeof(char)); word[j] = w[i+500]; c[j] = i; ++j; } } const int len = j; //字符數組、權重數組長度 if(len==1){ printf("請輸入大於1種字符!\n"); goto READ; } HuffmanCode HC;HuffmanTree HT; HuffmanCoding(HT,HC,word,c,len); PrintHuffmanCode(HC,word,c,len); i=0; printf("赫夫曼編碼後結果為:"); char code[1000]={‘\0‘}; while(s[i]!=‘\0‘){ strcat(code,EnCode(HC,c,s[i],len)); ++i; } printf("%s\n",code); printf("解碼結果為:%s",DeCode(code,HT)); printf("\n"); getchar(); return 0; }
運行截圖:
赫夫曼樹編碼解碼實例(C)