9. 樹--哈夫曼樹
阿新 • • 發佈:2019-01-02
哈夫曼樹(Huffman Tree)
定義
- 帶權路徑長度(WPL):設二叉樹有
n 個葉子結點,每個葉子結點帶有權值wk ,從根結點到每個葉子結點的長度為lk ,則每個葉子結點的帶權路徑長度之和為:WPL=∑nk=1wklk - 最優二叉樹或哈夫曼樹:WPL最小的二叉樹
哈夫曼樹的構造
假設有
- 將
w1,w2,...,wn 看成是有n 棵樹的森林(每棵樹僅有一個結點) - 在森林中選出兩個根結點的權值最小的樹合併,作為一棵新樹的左右子樹,且新樹的根結點權值為其左、右子樹根結點權值之和
- 從森林中刪除選取的兩棵樹,並將新樹加入森林
- 重複2、3步,直到森林中只剩一棵樹為止,該樹即為所求的哈夫曼樹
實現
演算法:
- 將所有的權值結點構造一個最小堆
- 重複
Size−1 次合併操作:
- 構建一個新結點
- 該結點的左右子結點為最小堆的堆頂元素
- 該結點的權值為左右子結點權值之和
- 插入到最小堆中
- 此時堆頂的結點為哈夫曼樹的根結點
typedef struct TreeNode *HuffmanTree;
struct TreeNode {
int Weight;
HuffmanTree Left, Right;
}
HuffmanTree Huffman(MinHeap H) {
// 假設H->Size個權值已經存在H->Elements[]->Weight裡
int i;
HuffmanTree T;
BuildMinHeap(H); // 將H->Elements[]按權值調整為最小堆
for (int i = 1; i < H->Size; i++) { // 做H->Size-1次合併
T = malloc(sizeof(struct TreeNode)); // 建立新結點
T->Left = DeleteMin(H); // 從最小堆中刪除一個結點,作為新T的左子結點
T->Right = DeleteMin(H); // 從最小堆中刪除一個結點,作為新T的右子結點
T->Weight = T->Left->Weight + T->Right->Weight; // 計算新權值
Insert(H, T); // 將新T插入最小堆
}
T = DeleteMin(H);
return T;
}
時間複雜度:
哈夫曼樹的特點
- 沒有度為1的結點
n 個葉子結點的哈夫曼樹共有2n−1 個結點- 哈夫曼樹的任意非葉結點的左右子樹交換後仍是哈夫曼樹
- 對同一組權值
{w1,w2,...,wn} `,存在不同構的兩棵哈夫曼樹
- 例,對一組權值
{1,2,3,3} ,不同構的兩棵哈夫曼樹:
- 例,對一組權值