哈夫曼树
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;
}