哈夫曼編碼(Huffman Coding),又稱霍夫曼編碼,是一種編碼方式。該方法徹底依據字符出現機率來構造異字頭的平均長度最短的碼字,有時稱之爲最佳編碼,通常就叫作Huffman編碼(有時也稱爲霍夫曼編碼)。數組
下圖是學生成績分佈圖: markdown
若是轉換成代碼一般是:if( sum < 60) result = 「不及格」; else if(sum < 70) result = 「及格」; else if(sum < 80) result = 「中等」; else if(sum < 90) result = 「良好」; else result = 「優秀」; 複製代碼若是是數量集很大的狀況下,這樣的比較會出現很嚴重的效率問題。由於人數比重比較多的是70-79分,想要獲得「中等」這個結果,須要通過3次判斷。其實根據所佔比例(權重),能夠生成一個更優質的二叉樹結構。
一般咱們使用WPL(樹的帶權路徑長度)來計算優質性,權重值就是學生所佔比例 x 樹到指定節點的路徑優化
咱們使用傳輸文字內容爲例: 編碼
內容ABCDEF分別用000、00一、0十、0十一、100、101表示。傳輸BADCADFEED這個內容。#include <stdio.h> #include "string.h" #include "stdlib.h" const int MaxValue = 100000;//初始化射電的權值最大值 const int MaxBit = 4;//初始最大編碼位數 const int MaxN = 10;//最大結點數 typedef struct HaffNode { int weight;//權重 int flag;//是否加入到合併到樹中。0:爲合併; 1:合併 int parent;//雙親結點下標 int lChild;//左孩子下標 int rChild;//右孩子下標 }HaffNode; typedef struct HaffCode{ int bit[MaxBit];//編碼數組 int length;//數組長度 int weight;//權重 }HaffCode; /** 構建哈弗曼樹 */ void haffman(int weight[], int n, HaffNode *haffTree) { //哈夫曼樹的結點度爲0或者2,因此n個葉子結點,總結點數爲2n-1 for (int i = 0; i < 2*n-1; i++) { if (i < n) { haffTree[i].weight = weight[i]; } else { haffTree[i].weight = 0; } haffTree[i].parent = 0; haffTree[i].flag = 0; haffTree[i].lChild = -1; haffTree[i].rChild = -1; } int value1, value2; int index1, index2; //構造哈夫曼樹 for (int i = 0; i < n-1; i++) { value1 = value2 = MaxValue; index1 = index2 = 0; //循環找出權重最小的兩個值 int j; for (j = 0; j < n+i; j++) { if (haffTree[j].weight < value1 && haffTree[j].flag == 0) { value2 = value1; index2 = index1; value1 = haffTree[j].weight; index1 = j; } else if (haffTree[j].weight < value2 && haffTree[j].flag == 0) { value2 = haffTree[j].weight; index2 = j; } } //將兩個最小值合併成一個子樹 haffTree[index1].parent = n+i; haffTree[index2].parent = n+i; haffTree[index1].flag = 1; haffTree[index2].flag = 1; haffTree[n+i].weight = haffTree[index1].weight + haffTree[index2].weight; haffTree[n+i].lChild = index1; haffTree[n+i].rChild = index2; } } /** 根據哈夫曼樹建立哈夫曼編碼 */ void haffmanCode(HaffNode haffTree[], int n, HaffCode haffCode[]) { //建立一個編碼結點 HaffCode *code = (HaffCode*)malloc(sizeof(HaffCode)); int child, parent; //遍歷到權重數組長度 for (int i = 0; i< n; i++) { code->length = 0; code->weight = haffTree[i].weight; child = i; parent = haffTree[i].parent; while (parent != 0) { if (haffTree[parent].lChild == child) { code->bit[code->length] = 0;//左孩子結點編碼0 } else { code->bit[code->length] = 1;//右孩子結點編碼1 } code->length ++; child = parent; parent = haffTree[child].parent; } //編碼是從子結點到父節點的順序生成的,是反的,因此要反向取編碼 int temp = 0; for (int j = code->length - 1; j>=0; j--) { temp = code->length - j - 1; haffCode[i].bit[temp] = code->bit[j]; } haffCode[i].length = code->length; haffCode[i].weight = code->weight; } } 複製代碼
int main(int argc, const char * argv[]) { // insert code here... printf("Hello, 哈夫曼編碼!\n"); int i, j, n = 4, m = 0; //權值 int weight[] = {2,4,5,7}; //初始化哈夫曼樹, 哈夫曼編碼 HaffNode *myHaffTree = malloc(sizeof(HaffNode)*2*n-1); HaffCode *myHaffCode = malloc(sizeof(HaffCode)*n); //當前n > MaxN,表示超界. 沒法處理. if (n>MaxN) { printf("定義的n越界,修改MaxN!"); exit(0); } //1. 構建哈夫曼樹 haffman(weight, n, myHaffTree); //2.根據哈夫曼樹獲得哈夫曼編碼 haffmanCode(myHaffTree, n, myHaffCode); //3. for (i = 0; i<n; i++) { printf("Weight = %d\n",myHaffCode[i].weight); for (j = 0; j<myHaffCode[i].length; j++) printf("%d",myHaffCode[i].bit[j]); m = m + myHaffCode[i].weight*myHaffCode[i].length; printf("\n"); } printf("Huffman's WPL is:%d\n",m); return 0; } 複製代碼