優先佇列與赫夫曼樹

2022-06-23 14:09:12 字數 2048 閱讀 3832

1.赫夫曼樹

帶權路徑最短的二叉樹,亦稱為最優二叉樹。在壓縮編碼方面,求解最小帶權和方面有著重要應用。往往機試題即是求最小的帶權長度和,如典型的合併石子問題。在解決這類問題時,一般可分為以下幾個方面:

首先將所有節點放入集合k,同時初始化全域性變數ans=0;

然後從集合k中選出最小權值的兩個節點,將他們的和sum放入k,更新ans為ans+sum,同時從k中刪除這兩個節點;

若集合k中只剩一個節點時,即為根節點,輸出的ans即為帶權路徑的總長度。

2.優先佇列

基於赫夫曼樹在求解最小帶權路徑和方面時,每次都是從集合k

kk中選取出最小的兩個值,我們可以利用優先佇列的特徵,維持一個小頂堆,每次取出小頂堆堆頂的兩個值,同時將他們的和放入堆中,利用ans

ansan

s統計每次的和,然後彈出這兩個值。當堆裡只有一個元素時,輸出的ans

ansan

s即為帶權的路徑和。在取出最小的兩個值時,時間複雜度可將為o(l

ogn)

o(logn)

o(logn

)

#include

using

namespace std;

priority_queue<

int> q;

//預設為大頂堆

priority_queue<

int,vector<

int>

,greater<

int>

> q2;

//小頂堆,注意末尾兩個》有間隔,否則可能報錯

3. 舉個栗子

題目:搬水果

題目描述

在一個果園裡,小明已經將所有的水果打了下來,並按水果的不同種類分成了若干堆,小明決定把所有的水果合成一堆。每一次合併,小明可以把兩堆水果合併到一起,消耗的體力等於兩堆水果的重量之和。當然經過 n‐1 次合併之後,就變成一堆了。小明在合併水果時總共消耗的體力等於每次合併所耗體力之和。 假定每個水果重量都為 1,並且已知水果的種類數和每種水果的數目,你的任務是設計出合併的次序方案,使小明耗費的體力最少,並輸出這個最小的體力耗費值。例如有 3 種水果,數目依次為 1,2,9。可以先將 1,2 堆合併,新堆數目為3,耗費體力為 3。然後將新堆與原先的第三堆合併得到新的堆,耗費體力為 12。所以小明總共耗費體力=3+12=15,可以證明 15 為最小的體力耗費值。

輸入描述:

每組資料輸入包括兩行,第一行是一個整數 n(1<=n<=10000),表示水果的種類數。第二行包含 n 個整數,用空格分隔,第 i 個整數(1<=ai<=1000)是第 i 種水果的數目。

輸出描述:

對於每組輸入,輸出一個整數並換行,這個值也就是最小的體力耗費值。輸入資料保證這個值小於 2^31。

示例1

輸入

3

9 1 2

輸出

思路:利用優先佇列維持一個小頂堆,然後用ans

ansan

s統計總的體力值即可。

#include

#include

#include

#include

using

namespace std;

priority_queue<

int,vector<

int>

,greater<

int>

> q;

//升序優先佇列實現最小堆

intmain()

int ans=0;

while

(q.size()

>1)

printf

("%d\n"

,ans)

;return0;

}

參考資料

《計算機考研機試指南》

根據赫夫曼樹求赫夫曼編碼

可能編譯時會有些語法小錯誤 比如分號, ,等 ,很容易就自己糾正了哦,思路絕對是完全正確的,所以用的話就自己試著改改吧,直接複製貼上,就正確,豈不是太沒寫 體驗了,自己改改才印象更加深刻的呢 根據赫夫曼樹求赫夫曼編碼 includeusing namespace std typedef struct...

有趣的赫夫曼樹

美國有個數學家叫赫夫曼,60年前他根據資料的使用概率,發明了一個二叉樹叫赫夫曼樹。 這個赫夫曼樹被用在了資料壓縮上,被稱為赫夫曼編碼,這是後...

赫夫曼樹編碼問題

定義 結點的帶權路徑長度為從該結點到樹根之間的路徑長度與結點上權的乘積。樹的帶權路徑長度為樹中所有葉子結點的帶權路徑長度之和。假設有n個權值...