【資料結構】哈夫曼樹的編碼與譯碼
阿新 • • 發佈:2018-12-24
#include <stdio.h> #include <malloc.h> #include <string.h> typedef struct { char info; int weight; int parent, lchild, rchild; } HTNode, *HuffmanTree; typedef char* *HuffmanCode; HuffmanTree HT; HuffmanCode HC; int n = 8; /* 在 HT[1...t] 中選擇 parent 不為 0 且權值最小的兩個結點, 其序號分別為 s1 和 s2 */ void Select(HuffmanTree HT, int t, int *s1, int *s2) { int i, temp1, temp2; temp1 = temp2 = 1000; for (i = 1; i <= t; i++) { if (HT[i].parent == 0 && (HT[i].weight < temp1 || HT[i].weight < temp2)) { if (temp1 < temp2) { temp2 = HT[i].weight; *s1 = i; } else { temp1 = HT[i].weight; *s2 = i; } } } /* s1 放較小的序號 */ if (*s1 > *s2) { i = *s1; *s1 = *s2; *s2 = i; } } HuffmanTree HuffmanCoding(int *w, int n, char *info) { // n 為字串個數 HuffmanTree HT, p; char *cd; int m, s1, s2, i, start, f, c; if (n <= 1) { return 0; } m = 2 * n - 1; HT = (HuffmanTree)malloc((m+1)*sizeof(HTNode)); p = HT + 1; for (i = 1; i <= n; ++i, ++p, ++w) { // 不用第 0 號單元 p->weight = *w; p->info = info[i-1]; 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; } for (i = n+1; i <= m; ++i) { // 在 HT 中選擇 parent 為 0 且 weight 最小的兩個結點,其序號分別為 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 *)); cd = (char *)malloc(n*sizeof(char)); cd[n-1] = '\0'; for (i = 1; i <= n; ++i) { start = n - 1; for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent) { // 從子葉到根逆向2求編碼 f 為父結點 c 為子結點 if (HT[f].lchild == c) { cd[--start] = '0'; } else { cd[--start] = '1'; } } HC[i] = (char *)malloc((n-start)*sizeof(char)); strcpy(HC[i], &cd[start]); } free(cd); return HT; } /* 編碼 */ void TextToCode() { char str[50]; int i, j, p; if (HT == NULL) { printf("請先進行初始化!\n"); return ; } printf("請輸入要編碼的文字(小寫英文字母):\n"); getchar(); gets(str); printf("編碼結果如下:\n"); p = strlen(str); for (i = 1; i <= p; i++) { for (j = 1; j <= n; j++) { if (str[i-1] == HT[j].info) { printf("%s", HC[j]); break; } } } printf("\n"); } /* 譯碼 */ void CodeToText() { int i = 1, j, key; int i1, i2; char str[100]; int a = 1; int m = 2 * n - 1; if (HT == NULL) { printf("請先進行初始化!\n"); return ; } printf("\n每個字母對應的哈夫曼編碼:\n"); /* 以一定格式輸出字母對應的編碼 */ for (i1 = i; i1 <= 2; i1++) { printf("┌———————┐ ┌———————┐ ┌———————┐ ┌———————┐\n"); for (i2 = 1; i2 <= 4; i2++) { printf("| %c:%-11s |", HT[a].info, HC[a]); a++; } printf("\n"); printf("└———————┘ └———————┘ └———————┘ └———————┘\n"); } printf("\n請輸入哈夫曼編碼:\n"); scanf("%s", str); j = strlen(str); key = m; printf("哈夫曼編碼譯碼如下:\n"); while (i <= j) { while (HT[key].lchild != 0) { if (str[i-1] == '0') { key = HT[key].lchild; i++; continue; } if (str[i-1] == '1') { key = HT[key].rchild; i++; continue; } } printf("%c", HT[key].info); key = m; } printf("\n"); } void menu() { printf("┌—————————————————————————┐\n"); printf("| (1) 構造哈夫曼樹 | \n"); printf("└—————————————————————————┘\n"); printf("┌—————————————————————————┐\n"); printf("| (2) 哈夫曼編碼 | \n"); printf("└—————————————————————————┘\n"); printf("┌—————————————————————————┐\n"); printf("| (3) 哈夫曼譯碼 | \n"); printf("└—————————————————————————┘\n"); printf("┌—————————————————————————┐\n"); printf("| (0) 退出 | \n"); printf("└—————————————————————————┘\n"); } int main() { int i, j = 1; int wei[8] = {5, 25, 7, 8, 14, 20, 3, 11}; char info[8] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; for (; j; ) { menu(); scanf("%d", &i); switch(i) { case 1: HT = HuffmanCoding(wei, n, info); break; case 2: TextToCode(); break; case 3: CodeToText(); break; case 0: j = 0; break; default: printf("輸入錯誤重新輸入\n"); } } return 0; }
注意:函式中的陣列 可自行更改(其中 中的值對應 中字元的權值)