哈夫曼樹(C++優先隊列的使用)
阿新 • • 發佈:2018-02-09
name sub pan main 道理 輸出 tor 數據 排序。
給定n個權值作為n個葉子結點,構造一棵二叉樹,若帶權路徑長度達到最小,稱為哈夫曼樹(Huffman Tree)。哈夫曼樹是帶權路徑長度最短的樹,權值較大的結點離根較近。
構造
假設有n個權值,則構造出的哈夫曼樹有n個葉子結點。 n個權值分別設為 w1、w2、…、wn,則哈夫曼樹的構造規則為:
(1) 將w1、w2、…,wn看成是有n 棵樹的森林(每棵樹僅有一個結點);
(2) 在森林中選出兩個根結點的權值最小的樹合並,作為一棵新樹的左、右子樹,且新樹的根結點權值為其左、右子樹根結點權值之和;
(3)從森林中刪除選取的兩棵樹,並將新樹加入森林;
(4)重復(2)、(3)步,直到森林中只剩一棵樹為止,該樹即為所求得的哈夫曼樹
題目描述
哈夫曼樹,第一行輸入一個數n,表示葉結點的個數。需要用這些葉結點生成哈夫曼樹,根據哈夫曼樹的概念,這些結點有權值,即weight,題目需要輸出所有結點的值與權值的乘積之和。輸入描述:
輸入有多組數據。 每組第一行輸入一個數n,接著輸入n個葉節點(葉節點權值不超過100,2<=n<=1000)。
輸出描述:
輸出權值。示例1
輸入
5 1 2 2 5 9
輸出
37
解題思路:做這題一開始想得是每次選擇兩個數據相加後馬上進行一次快速排序。
這個方法對小數據可以,但是對PAT那種變態大數據就運行超時了。
1 #include<stdio.h> 2#include<stdlib.h> 3 4 int cmp( const void *a, const void *b) 5 { 6 return *(int *)a - *(int *)b; //從小到大排序 7 } 8 int num[1002]; 9 int main() 10 { 11 int n; 12 int ans; 13 int i; 14 while( scanf("%d",&n)!=EOF) 15 { 16 for( i=0; i<n; i++) 17 {18 scanf("%d",&num[i]); 19 } 20 ans = 0; 21 for( i=0; i<n-1; i++) 22 { 23 //切記這裏是i<n-1,最後一個數字就是答案 24 qsort( &num[i],n-i,sizeof(num[0]),cmp); 25 ans += num[i]+ num[i+1]; 26 num[i+1] = num[i]+ num[i+1]; 27 } 28 printf("%d\n",ans); 29 } 30 31 return 0; 32 33 }
上面的做法容易超時,下面使用C++利用優先隊列構建小頂堆來實現哈夫曼樹速度更快,道理都是一樣的,換了個實現方法。
1 #include<stdio.h> 2 #include<queue> 3 using namespace std; 4 priority_queue<int, vector<int>,greater<int> > Q; //建立一個小頂堆 5 //priority_queue<int> Q; //默認建立一個大頂堆 6 7 int main() 8 { 9 int n; 10 int ans,temp1,temp2; 11 int i; 12 13 while( scanf("%d",&n)!=EOF) 14 { 15 while( Q.empty()==false) Q.pop(); //清除堆中元素 16 17 for( i=1; i<=n; i++) 18 { 19 scanf("%d",&temp1); 20 Q.push(temp1); 21 } 22 ans = 0; 23 while( Q.size()>1) //當堆中元素個數大於1 24 { 25 temp1 =Q.top(); 26 Q.pop(); 27 temp2 =Q.top(); 28 Q.pop(); //取出堆中兩個最小的元素 29 ans += temp1+temp2; 30 Q.push( temp1+temp2); //將該雙親結點的權值放回堆中 31 } 32 printf("%d\n",ans); 33 } 34 return 0; 35 }
哈夫曼樹(C++優先隊列的使用)