最小堆建立

题目来源: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。如果有的话,看到的给我说声,在此说声谢谢。本人邮箱:greenteak1992@gmail.com

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值