哈夫曼樹(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} ,不同構的兩棵哈夫曼樹:
- 例,對一組權值