C++最優(yōu)二叉樹哈夫曼樹算法解析
定義
哈夫曼樹又稱最優(yōu)二叉樹,是一種帶權(quán)路徑長度最短的二叉樹。
所謂樹的帶權(quán)路徑長度,就是樹中所有的葉結(jié)點(diǎn)的權(quán)值乘上其到根結(jié)點(diǎn)的路徑長度(若根結(jié)點(diǎn)為0層,葉結(jié)點(diǎn)到根結(jié)點(diǎn)的路徑長度為葉結(jié)點(diǎn)的層數(shù))。
樹的路徑長度是從樹根到每一結(jié)點(diǎn)的路徑長度之和,記為WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N個(gè)權(quán)值Wi(i=1,2,...n)構(gòu)成一棵有N個(gè)葉結(jié)點(diǎn)的二叉樹,相應(yīng)的葉結(jié)點(diǎn)的路徑長度為Li(i=1,2,...n)。
可以證明哈夫曼樹的WPL是最小的。
給定N個(gè)權(quán)值作為N個(gè)葉子結(jié)點(diǎn),構(gòu)造一棵二叉樹,若該樹的帶權(quán)路徑長度達(dá)到最小,稱這樣的二叉樹為最優(yōu)二叉樹,也稱為哈夫曼樹(Huffman Tree)。
哈夫曼樹是帶權(quán)路徑長度最短的樹,權(quán)值較大的結(jié)點(diǎn)離根較近。
實(shí)例引入
現(xiàn)在有這樣一個(gè)經(jīng)典問題:果子合并。
現(xiàn)在得到很多果子,需要把這些果子合并成一堆。每一次合并,可以把兩堆果子合并到一起,消耗的體力等于兩堆果子的重量之和??梢钥闯?,所有的果子經(jīng)過 n−1 次合并之后,就只剩下一堆了。在合并果子時(shí)總共消耗的體力等于每次合并所耗體力之和。
假定每個(gè)果子重量都為 1,并且已知果子的種類數(shù)和每種果子的數(shù)目,你的任務(wù)是設(shè)計(jì)出合并的次序方案,使耗費(fèi)的體力最少,并輸出這個(gè)最小的體力耗費(fèi)值。
例如有 3 種果子,數(shù)目依次為 1,2,9??梢韵葘?nbsp;1、2 堆合并,新堆數(shù)目為 3,耗費(fèi)體力為 3。
接著,將新堆與原先的第三堆合并,又得到新的堆,數(shù)目為 12,耗費(fèi)體力為 12。所以總共耗費(fèi)體力=3+12=15??梢宰C明 15 為最小的體力耗費(fèi)值。
我們把這幾個(gè)果子看成樹的葉子
然后通過逐次合并其中兩個(gè)葉子(果子),使根節(jié)點(diǎn)的權(quán)值最小,根據(jù)上面的分析先合并1,2得到3,之后合并3,9得到12。
其中我們要計(jì)算的便是產(chǎn)生的新節(jié)點(diǎn)的權(quán)值,把這先權(quán)值相加,即是最后要求的體力值。
進(jìn)一步分析可以發(fā)現(xiàn),假設(shè)初始狀態(tài)下我們有四個(gè)點(diǎn),是四個(gè)點(diǎn)之間的最優(yōu)解問題,當(dāng)我們合并其中兩個(gè)點(diǎn)之后就變成了三個(gè)點(diǎn)的最優(yōu)解問題,以此類推;
而且如果保證每次選的兩個(gè)數(shù)都是最小的(最優(yōu)的),那么接下來都是最優(yōu)解的情況了。
由于數(shù)據(jù)輸入是并不是按照從小到大排列,故可以使用小根堆來做。
代碼
#include <bits/stdc++.h> using namespace std; int main() { int n; scanf("%d", &n); priority_queue<int, vector<int>, greater<int>> heap; while (n--) { int x; scanf("%d", &x); heap.push(x); } int res = 0; while (heap.size() > 1) { int a = heap.top(); heap.pop(); int b = heap.top(); heap.pop(); res += a + b; heap.push(a + b); } printf("%d\n", res); return 0; }
到此這篇關(guān)于C++最優(yōu)二叉樹哈夫曼樹算法解析的文章就介紹到這了,更多相關(guān)C++哈夫曼樹內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Qt圖形圖像開發(fā)之曲線圖模塊QCustomplot庫生成靜態(tài)、動(dòng)態(tài)曲線詳細(xì)教程圖解
這篇文章主要介紹了Qt圖形圖像開發(fā)之曲線圖模塊QCustomplot庫畫靜態(tài)、動(dòng)態(tài)曲線詳細(xì)教程圖解,需要的朋友可以參考下2020-03-03OpenCV實(shí)現(xiàn)鼠標(biāo)框選并顯示框選區(qū)域
這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)鼠標(biāo)框選并顯示框選區(qū)域,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08C語言動(dòng)態(tài)與靜態(tài)分別實(shí)現(xiàn)通訊錄詳細(xì)過程
這篇文章主要為大家介紹了C語言動(dòng)態(tài)與靜態(tài)分別實(shí)現(xiàn)通訊錄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-02-02淺談c++如何實(shí)現(xiàn)并發(fā)中的Barrier
這篇文章主要介紹了淺談c++如何實(shí)現(xiàn)并發(fā)中的Barrier,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07C語言實(shí)現(xiàn)掃雷小游戲(適合初學(xué)者)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)掃雷小游戲,適合初學(xué)者練習(xí),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03Qt圖形圖像開發(fā)曲線圖表模塊QChart庫基本用法、各個(gè)類之間的關(guān)系說明
這篇文章主要介紹了Qt圖形圖像開發(fā)曲線圖表模塊QChart庫基本用法、各個(gè)類之間的關(guān)系說明,需要的朋友可以參考下2020-03-03