哈夫曼樹(Huffman Tree)
帶權路徑長度(WPL):設二叉樹有n個葉子結點,每個葉子結點帶有權值Wk,從根節點到每個葉子結點的長度為Lk,則每個葉子結點帶權路徑長度之和就是(wk* Lk)求和
最優二叉樹或哈夫曼樹:WPL最小的二叉樹
哈夫曼樹的構造:每次把權值最小的兩棵二叉樹合並
1 HuffmanTree Huffman(MinHeap H) 2 { 3 //這里最小堆的元素類型為HuffmanTree,排序的原則是結點的權值數據 4 //假設H->Size個權值已經存在在H->Data[]->weight里 5 int i, N; 6 HuffmanTree T; 7 8 BuildMinHeap(H); //根據結點的權值將H調整為最小堆 9 N = H->Size; 10 for (i = 1; i < N; i++) //做H->Size - 1次合並 11 { 12 T = (HuffmanTree)malloc(sizeof(struct HTNode)); //創建一個新的哈夫曼結點 13 T->Left = DeleteMin(H); //將最小堆中的最小元素,即根節點刪除后返回,作為這個哈夫曼結點的左子結點 14 T->Right = DeleteMin(H); //再次將最小堆中的根節點刪除后返回,作為這個哈夫曼樹的右子結點 15 //哈夫曼節點的權值等於左右子節點的權值之和 16 T->weight = T->Left->weight + T->Right->weight; 17 Insert(H, T); 18 } 19 20 return DeleteMin(H); //最小堆中最后一個元素即使指向哈夫曼樹根節點的指針 21 }
哈夫曼樹的特點:
沒有度為1的結點
n個葉子結點的哈夫曼樹共有2n-1個結點
哈夫曼樹的任意非葉結點的左右子樹交換后仍是哈夫曼樹
對同一組權值,存在不同構的兩棵哈夫曼樹,但兩棵樹的WPL相等
哈夫曼編碼(文件壓縮):
給定一段字符串,如何對字符進行編碼,可以使得該字符串的編碼存儲空間最少
前綴碼:(prefix code)任何字符的編碼都不是另一字符編碼的前綴,可避免二義性
二叉樹表示法:每個字符通過從根節點開始用0指示左分支,用1指示右分支而已記錄路徑的方法表示出來
用二叉樹進行編碼:
(1)左右分支:0、 1
(2)字符只在葉結點上
用哈夫曼樹的規則構造這棵二叉樹
哈夫曼編碼對應的解壓過程:
依次讀入文件的二進制碼,從哈夫曼樹的根節點出發,若當前讀入0,則走向左孩子,否則走向右孩子。
一旦到達某一葉子時便譯出相應的字符。然后重新從根出發繼續下一個字符的譯碼,直至文件結束