题目来源:http://dsalgo.openjudge.cn/201409week5/2/
最小堆建立
题目:实现最小堆两个功能:
1、增加一个元素
2、输出并删除最小堆中的最小的数
输入:
第一行输入一个整数t,代表测试数据的组数。
对于每组测试数据,第一行输入一个整数n,代表操作的次数。
每次操作首先输入一个整数type。
当type=1,增添操作,接着输入一个整数u,代表要插入的元素。
当type=2,输出删除操作,输出并删除数组中最小的元素。
1<=n<=100000。
输出
每次删除操作输出被删除的数字。
样例输入
2
5
1 1
1 2
1 3
2
2
4
1 5
1 1
1 7
2
样例输出
1
2
1
解题思路:建立最小堆最终要的就是元素的插入与删除。每插入一个元素要确定元素要插入的位置,确定是向上筛还是向下筛。没删除一个元素要将最后一个元素放到跟的位置,然后进行向下筛的操作。
代码片:
#include<iostream>
using namespace std;
template <class T>
class MinHeap{
private:
T* heapArray; //存放堆数据的数组
int CurrentSize;//当前堆中元素数目
int MaxSize; //堆所能容纳的最大元素的数目
public:
void BuildHeap();//建堆
MinHeap(int n, int C, int M);//构造函数
//MinHeap(T* h, int C=0, int M = 100000);//构造函数
~MinHeap(){ delete[] heapArray; }//析构函数
/*bool isLeaf(int pos)const//如果是叶节点,返回true
{return (pos >= n / 2) && (pos < n); }*/
int leftchild(int pos)const//返回左孩子的位置
{
return 2 * pos + 1;
}
int rightchild(int pos)const//返回右孩子的位置
{
return 2 * pos + 2;
}
int parent(int pos)const//返回父节点的位置
{
return (pos - 1) / 2;
}
bool Remove(int pos, T& node);//删除给定下标的元素
bool Insert(const T& newNode);//向堆中插入新元素newNode
bool RemoveMin(T& node); //堆中删除最小元素
void SiftUp(int position);//从position开始向上调整
void SiftDown(int left);//筛选法函数,参数left表示开始处理的数组下标
};
/*template <class T> MinHeap<T>::MinHeap(T* h,int C=0,int M=100000 ){//构造函数
heapArray = h;
CurrentSize = C;
MaxSize = M;
BuildHeap();
}*/
template<class T> MinHeap<T>::MinHeap(int n, int C, int M){//构造函数
heapArray = new T(n);
CurrentSize = C;
MaxSize = M;
BuildHeap();
}
template <class T> void MinHeap<T>::BuildHeap(){ //建堆
for (int i = CurrentSize / 2 - 1; i >= 0; i++)
SiftDown(i);
}
template<class T>void MinHeap<T>::SiftUp(int position){//从positon开始向上调整
int pos = position;
T temp = heapArray[pos];
while (pos>0 && heapArray[parent(pos)]>temp)
{
heapArray[pos] = heapArray[parent(pos)];
pos = parent(pos);
}
heapArray[pos] = temp;
}
template<class T>void MinHeap<T>::SiftDown(int left){//筛选法函数,参数left表示开始处理的数组下标
int i = left;
int j = 2 * i + 1;
T temp = heapArray[i];
while (j < CurrentSize)
{
if (j < CurrentSize - 1 && heapArray[j] > heapArray[j + 1])
j++;//j指向元素值大的元素
if (temp>heapArray[j])
{
heapArray[i] = heapArray[j];
i = j;
j = 2 * i + 1;
}
else break;
}
heapArray[i] = temp;
}
template<class T> bool MinHeap<T>::Remove(int pos, T& node){//删除给定下标的元素
if (pos<0 && pos>CurrentSize)
return false;
if (CurrentSize == 0)
return false;
T temp = heapArray[pos];
heapArray[pos] = heapArray[--CurrentSize];
if (heapArray[parent(pos)] > heapArray[pos])
SiftUp(pos);
else SiftDown(pos);
node = temp;
return true;
}
template<class T> bool MinHeap<T>::Insert(const T& newNode){//向堆中添加新元素newNode
if (CurrentSize == MaxSize)
return false;
heapArray[CurrentSize] = newNode;
SiftUp(CurrentSize);
CurrentSize++;
return true;
}
template<class T>bool MinHeap<T>::RemoveMin(T& node){//删除堆中的最小元素
int c;
c=Remove(0, node);
if (c==false)
return false;
else return true;
}
int main()
{
int j, c,cite;
int s = 100000;
cin >> j;
while (j--)
{
MinHeap<int>op(s, 0, 100000);
int i;
cin >> i;
while (i--)
{
int Ti, u;
cin >> Ti;
if (Ti == 1)
{
cin >> u;
op.Insert(u);
}
else {
cite=op.RemoveMin(c);
if (cite!=false)
cout << c << endl;
}
}
}
return 0;
}
总结: 最小堆的建立主要的就是SiftDown和SiftUp。弄清楚最小堆插入和删除都必须维护最小堆的结构。上面的代码是我个人所写,可能出现bug。如果有的话,看到的给我说声,在此说声谢谢。