1. 程式人生 > >9. 樹--哈夫曼樹

9. 樹--哈夫曼樹

哈夫曼樹(Huffman Tree)

定義

  • 帶權路徑長度(WPL):設二叉樹有n個葉子結點,每個葉子結點帶有權值wk,從根結點到每個葉子結點的長度為lk,則每個葉子結點的帶權路徑長度之和為:WPL=nk=1wklk
  • 最優二叉樹或哈夫曼樹:WPL最小的二叉樹

哈夫曼樹的構造

假設有n個權值結點,則構造出的哈夫曼樹有n個葉子結點:

  1. w1,w2,...,wn看成是有n棵樹的森林(每棵樹僅有一個結點)
  2. 在森林中選出兩個根結點的權值最小的樹合併,作為一棵新樹的左右子樹,且新樹的根結點權值為其左、右子樹根結點權值之和
  3. 從森林中刪除選取的兩棵樹,並將新樹加入森林
  4. 重複2、3步,直到森林中只剩一棵樹為止,該樹即為所求的哈夫曼樹

實現

演算法:

  1. 將所有的權值結點構造一個最小堆
  2. 重複Size1次合併操作:
    1. 構建一個新結點
    2. 該結點的左右子結點為最小堆的堆頂元素
    3. 該結點的權值為左右子結點權值之和
    4. 插入到最小堆中
  3. 此時堆頂的結點為哈夫曼樹的根結點
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; }

時間複雜度:O(NlogN)

哈夫曼樹的特點

  • 沒有度為1的結點
  • n個葉子結點的哈夫曼樹共有2n1個結點
  • 哈夫曼樹的任意非葉結點的左右子樹交換後仍是哈夫曼樹
  • 對同一組權值{w1,w2,...,wn} `,存在不同構的兩棵哈夫曼樹
    • 例,對一組權值{1,2,3,3} ,不同構的兩棵哈夫曼樹:

image