#include <stdio.h> #include <stdlib.h> #include <string.h> typedef int ELEMTYPE; // 哈夫曼樹結點結構體 typedef struct HuffmanTree { ELEMTYPE weight; ELEMTYPE id; // id用來主要用以區分權值相同的結點,這里代表了下標 struct HuffmanTree* lchild; struct HuffmanTree* rchild; }HuffmanNode; // 構建哈夫曼樹 HuffmanNode* createHuffmanTree(int* a, int n) { int i, j; HuffmanNode **temp, *hufmTree; temp = malloc(n*sizeof(HuffmanNode)); for (i=0; i<n; ++i) // 將數組a中的權值賦給結點中的weight { temp[i] = (HuffmanNode*)malloc(sizeof(HuffmanNode)); temp[i]->weight = a[i]; temp[i]->id = i; temp[i]->lchild = temp[i]->rchild = NULL; } for (i=0; i<n-1; ++i) // 構建哈夫曼樹需要n-1合並 { int small1=-1, small2; // small1、small2分別作為最小和次小權值的下標 for (j=0; j<n; ++j) // 先將最小的兩個下標賦給small1、small2(注意:對應權值未必最小) { if (temp[j] != NULL && small1==-1) { small1 = j; continue; } else if(temp[j] != NULL) { small2 = j; break; } } for (j=small2; j<n; ++j) // 比較權值,挪動small1和small2使之分別成為最小和次小權值的下標 { if (temp[j] != NULL) { if (temp[j]->weight < temp[small1]->weight) { small2 = small1; small1 = j; } else if (temp[j]->weight < temp[small2]->weight) { small2 = j; } } } hufmTree = (HuffmanNode*)malloc(sizeof(HuffmanNode)); hufmTree->weight = temp[small1]->weight + temp[small2]->weight; hufmTree->lchild = temp[small1]; hufmTree->rchild = temp[small2]; temp[small1] = hufmTree; temp[small2] = NULL; } free(temp); return hufmTree; } // 以廣義表的形式打印哈夫曼樹 void PrintHuffmanTree(HuffmanNode* hufmTree) { if (hufmTree) { printf("%d", hufmTree->weight); if (hufmTree->lchild != NULL || hufmTree->rchild != NULL) { printf("("); PrintHuffmanTree(hufmTree->lchild); printf(","); PrintHuffmanTree(hufmTree->rchild); printf(")"); } } } // 遞歸進行哈夫曼編碼 void HuffmanCode(HuffmanNode* hufmTree, int depth) // depth是哈夫曼樹的深度 { static int code[10]; if (hufmTree) { if (hufmTree->lchild==NULL && hufmTree->rchild==NULL) { printf("id為%d權值為%d的葉子結點的哈夫曼編碼為 ", hufmTree->id, hufmTree->weight); int i; for (i=0; i<depth; ++i) { printf("%d", code[i]); } printf("\n"); } else { code[depth] = 0; HuffmanCode(hufmTree->lchild, depth+1); code[depth] = 1; HuffmanCode(hufmTree->rchild, depth+1); } } } // 哈夫曼解碼 void HuffmanDecode(char ch[], HuffmanNode* hufmTree, char string[]) // ch是要解碼的01串,string是結點對應的字符 { int i; int num[100]; HuffmanNode* tempTree = NULL; for (i=0; i<strlen(ch); ++i) { if (ch[i] == '0') num[i] = 0; else num[i] = 1; } if(hufmTree) { i = 0; // 計數已解碼01串的長度 while(i<strlen(ch)) { tempTree = hufmTree; while(tempTree->lchild!=NULL && tempTree->rchild!=NULL) { if (num[i] == 0) { tempTree = tempTree->lchild; } else { tempTree = tempTree->rchild; } ++i; } printf("%c", string[tempTree->id]); // 輸出解碼后對應結點的字符 } } } int main() { int i, n; printf("請輸入葉子結點的個數:\n"); while(1) { scanf("%d", &n); if (n>1) break; else printf("輸入錯誤,請重新輸入n值!"); } int* arr; arr=(int*)malloc(n*sizeof(ELEMTYPE)); printf("請輸入%d個葉子結點的權值:\n", n); for (i=0; i<n; ++i) { scanf("%d", &arr[i]); } char ch[100], string[100]; printf("請連續輸入這%d個葉子結點各自所代表的字符:\n", n); fflush(stdin); // 強行清除緩存中的數據,也就是上面輸入權值結束時的回車符 gets(string); HuffmanNode* hufmTree = NULL; hufmTree = createHuffmanTree(arr, n); printf("此哈夫曼樹的廣義表形式為:\n"); PrintHuffmanTree(hufmTree); printf("\n各葉子結點的哈夫曼編碼為:\n"); HuffmanCode(hufmTree, 0); printf("要解碼嗎?請輸入編碼:\n"); gets(ch); printf("解碼結果為:\n"); HuffmanDecode(ch, hufmTree, string); printf("\n"); free(arr); free(hufmTree); return 0; }