資料結構:赫夫曼樹和赫夫曼編碼的儲存表示
阿新 • • 發佈:2018-12-22
#include <stdio.h> #include <stdlib.h> #include <string.h> #define UINT_MAX 100 //假設各結點的權值不會超過100 typedef struct { unsigned int weight; //權值 unsigned int parent, lchild, rchild; }HTNode, *HuffmanTree; //動態分配陣列儲存赫夫曼樹 typedef char **HuffmanCode; //動態分配陣列儲存赫夫曼編碼表 int Min(HuffmanTree &HT,int i) { //在HT[1...i]中選擇parent為0且權值最小的結點 //返回該結點的下標值 //此函式被Select函式呼叫 int j; unsigned int k = UINT_MAX;//假設各結點的權值不會超過UINT_MAX int flag; for(j = 1; j <= i; ++j) { if(HT[j].weight < k && HT[j].parent == 0)//用父結點是否為0來判斷此結點是否已經被選過 { k = HT[j].weight; flag = j; } } HT[flag].parent = 1;//作個標記,說明已經被選擇了,因為在Select函式中要選擇權值小的兩個結點 return flag; } void Select(HuffmanTree &HT, int i, int &s1, int &s2) { //在HT[1...i]中選擇parent為0且權值最小的兩個結點,其序號分別為s1,s2 //s1 <= s2 s1 = Min(HT,i); s2 = Min(HT,i); } void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n) { //w存放n個字元的權值(均>0),構造赫夫曼樹HT,並求出n個字元的赫夫曼編碼HC if(n <= 1) return ; int m = 2*n - 1; //嚴格的二叉樹中,有n個葉子結點,就有2n - 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).weight = *w; (*p).parent = 0; (*p).lchild = 0; (*p).rchild = 0; } for(;i<=m;++i,++p) { (*p).weight = 0; (*p).parent = 0; (*p).lchild = 0; (*p).rchild = 0; } int s1,s2;//儲存權值最小的兩個結點的序號 for(i=n+1; i <= m; ++i)//建立赫夫曼樹 { 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個字元編碼的頭指標向量,0號單元未用 char *cd = (char *)malloc(n*sizeof(char)); //分配求編碼的工作空間 cd[n-1] = '\0'; //編碼結束符 int start; unsigned chld,father; for(i = 1; i <= n; ++i) //逐個字元求赫夫曼編碼 { start = n-1; //從編碼結束符的位置開始 for(chld=i, father=HT[i].parent; father!=0; chld=father, father=HT[father].parent)//從葉子到根逆向求編碼 { if(HT[father].lchild == chld) 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); //釋放工作空間 } int main() { HuffmanTree HT; HuffmanCode HC; printf("請輸入權值的個數:\n"); int n; scanf("%d",&n); int *w = (int*)malloc(n*sizeof(int)); printf("請分別輸入%d個權值:\n",n); int i; for(i=0; i<n; ++i) { scanf("%d",w+i); } HuffmanCoding(HT, HC, w, n); printf("赫夫曼樹為:\n"); printf("NO\tweight\tparent\tlchild\trchild\n"); for(i=1; i <= 2*n-1; ++i) { printf("%d\t%d\t%d\t%d\t%d\n", i, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild); } printf("赫夫曼編碼為:\n"); for(i = 1; i <= n; ++i) printf("%d| |-->%s\n", i, HC[i]); return 0; }