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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章