哈夫曼樹
1、題目和要求
時間限制:1s,內存限制:32MB,特殊判題:否
2、總結
1)構建小頂堆。使用priority_queue<int> heap
構建的堆默認是大頂堆,使用priority_queue<int,vector<int>,greater<int> > heap
構建小頂堆。
2)有一個非常重要的概念:所有構造得到的中間結點(即哈夫曼樹上非葉子結點)權值和即爲該哈夫曼樹的帶權路徑和。記住這句話省了好多事……
3)有許多小細節需要注意:
- 取出小頂堆頂後,需判斷該值是否在輸入序列中。
- 需要考慮,如果相加後的值和輸入序列中的某個值相等怎麼辦。
3、思路
- 將數據輸入小頂堆
- 每次取小頂堆的頂,構建非葉子節點。同時採用數組存儲所有節點
- 輸出帶權路徑和
4、代碼
#include <iostream>
#include <queue>
using namespace std;
#define N 1000
class Node
{
private:
int level;
int value;
public:
void setNode(int l,int v)
{
level = l;
value = v;
}
int getLevel()
{
return level;
}
int getValue()
{
return value;
}
};
int value[N];//value:記錄輸入數值
//用於判斷取出的小頂堆頂是否是輸入的數值。
//如果是則加入HaffmanTree[N];如果不是,則不加入
int exitOrnot(int length,int a)
{
for(int i=0; i<length; i++)
{
if(value[i]==a)
{
value[i]=-1;
return i;
}
}
}
int main()
{
//1.將數據輸入小頂堆
priority_queue< int,vector<int>,greater<int> > inputList;
Node HaffmanTree[N],HaffmanNode1,HaffmanNode2;
int nodeNumber,m;//nodeNumber:記錄結點個數
int level=0,i=0;//level:記錄結點層數 i:記錄數組位置
int p1,p2;//p1,p2:記錄相加的兩個結點的數值
cin>>nodeNumber;
m=0;
while(m<nodeNumber)
{
cin>>value[m];
inputList.push(value[m]);
m++;
}
//2.每次取小頂堆的頂,構建節點,採用數組存儲所有節點
while(i<nodeNumber)
{
HaffmanNode1.setNode(level,inputList.top());
inputList.pop();
HaffmanNode2.setNode(level,inputList.top());
inputList.pop();
p1 = exitOrnot (nodeNumber, HaffmanNode1.getValue());
p2 = exitOrnot (nodeNumber, HaffmanNode2.getValue());
if(p1>=0 && p1<nodeNumber)
{
HaffmanTree[i++].setNode(HaffmanNode1.getLevel(),HaffmanNode1.getValue());
}
if(p2>=0 && p2<nodeNumber)
{
HaffmanTree[i++].setNode(HaffmanNode2.getLevel(),HaffmanNode2.getValue());
}
inputList.push(HaffmanNode1.getValue() + HaffmanNode2.getValue());
level++;
}
//3.輸出
int WPL=0;
for(i=0; i<nodeNumber; i++)
{
WPL += HaffmanTree[i].getValue() * (nodeNumber - 1 - HaffmanTree[i].getLevel());
}
cout<<WPL<<endl;
}