2017计算机学科夏令营上机考试 G:实现堆结构 优先队列

本文介绍了一种利用最小堆实现优先队列的方法,包括两种操作:添加元素及输出并删除最小元素。提供了两种实现思路:一是手动实现堆的操作,二是利用STL中的优先队列。代码示例清晰地展示了这两种方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

考察优先队列
总时间限制: 3000ms内存限制: 65536kB 题目
描述

定义一个数组,初始化为空。在数组上执行两种操作:
1、增添1个元素,把1个新的元素放入数组。
2、输出并删除数组中最小的数。

使用堆结构实现上述功能的高效算法。

输入

第一行输入一个整数t,代表测试数据的组数。
对于每组测试数据,第一行输入一个整数n,代表操作的次数。
每次操作首先输入一个整数type。
当type=1,增添操作,接着输入一个整数u,代表要插入的元素。
当type=2,输出删除操作,输出并删除数组中最小的元素。
1<=n<=100000。

输出

每次删除操作输出被删除的数字。

样例输入

4
1 5
1 1
1 7
2

样例输出

1

提示
每组测试数据的复杂度为O(nlogn)的算法才能通过本次,否则会返回TLE(超时)
需要使用最小堆结构来实现本题的算法

思路1普通方法:
1 用全局数组实现heap,要熟悉downadjust(low ,high)和upadjust(low , high)的书写
2 注意heap数组从下标1开始存数,否则左右孩子计算公式(2*low,2*low+1)不再正确[heap[++k] = num]
3 入堆向上调整 出堆向下调整 建堆从右往左从下往上调整(逆序的for+向下调整)
代码:

#include<map>
#include<string>
#include<set>
#include<cmath>
#include<sstream>
#include <algorithm>
#include<queue>
#include<stack>
using namespace std;
//小顶堆
int heap[100000];//最多100000次操作
void downadjust(int tag,int k)//建堆和删除向下调整
{
    while(2*tag<=k)
    {
        int minnum;
        if(2*tag+1<=k)
            minnum=min(heap[2*tag],heap[2*tag+1]);
        else //可能没有右孩子
            minnum = heap[2*tag];
        if(heap[tag]>minnum)
        {
                if(minnum==heap[2*tag])
                         {
                             heap[2*tag]=heap[tag];
                             heap[tag]=minnum;
                             tag=2*tag;//向下调整
                         }
                else
                         {
                             heap[2*tag+1]=heap[tag];
                             heap[tag]=minnum;
                             tag = 2*tag+1;//向下调整
                         }
        }
        else break;//根节点达到最小,循环结束
    }
}

void upadjust(int low,int high)//入堆向上调整
{
    while(low>=1)
    {
            int minnum;
            if(2*low+1<=high)
                minnum=min(heap[2*low],heap[2*low+1]);
            else //可能没有右孩子
                minnum = heap[2*low];

            if(heap[low]>minnum)
                {
                    if(minnum==heap[2*low])
                         {
                             heap[2*low]=heap[low];
                             heap[low]=minnum;
                             low=low/2;//向上调整
                         }
                   else
                         {
                             heap[2*low+1]=heap[low];
                             heap[low]=minnum;
                             low = (low-1)/2;//向上调整
                         }
                }
                else break;
    }
}
int main()
{
    long long int n;
    freopen("input.txt","r",stdin);
    int k=0,type,num;
    while(cin>>n)
    {
        int i=0;
        while(i<n)
        {
            i++;
            cin>>type;
            if(type==1)
            {
                cin>>num;
                heap[++k]=num;
                if(k!=1)  upadjust(k/2,k);
            }
            else
            {
                int out_num=heap[1];
                cout<<out_num<<endl;
                heap[1]=heap[k--];
                downadjust(1,k);
            }
        }
    }
    return 0;
}

思路2使用优先队列:
优先队列的应用。注意优先队列是用堆实现的,所以对优先队里push()、pop()操作的时间复杂度都是O(nlongn)
初始化优先队列需要三个参数,第一个参数是元素类型,第二个参数为容器类型,第三个参数是比较算子。
priority_queue 《int ,vector《int》,greater《int》》 p; 大的放在队尾(小顶堆)
priority_queue 《int ,vector《int》,less《int》》 p; 小的放在队尾(大顶堆)
priority_queue 《int ,vector《int》,cmp 》 p; 注意队列的cmp和排序sort中的cmp作用相反(队列中cmp<是队首到队尾降序,排序中cmp<则是数组首到数组尾升序)

需要熟悉队列操作:
1 q.top()访问堆顶
2 q.push()入堆
3 q.pop()出堆
4 cmp需要写成结构体形式

struct cmp{  
    bool operator()(int a,int b){  
        return a>b;//优先输出值小的   
    }  
};

5 定义堆需要注意最后两个> 之间有一个空格

代码:

#include <iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<string>
#include<set>
#include<cmath>
#include<sstream>
#include <algorithm>
#include<queue>
#include<stack>
using namespace std;
int type,num;
struct cmp{  
    bool operator()(int a,int b){  
        return a>b;//优先输出值小的   
    }  
};
int main()
{
    //freopen("input.txt","r",stdin);
    priority_queue<int ,vector<int>,greater<int> > q;
    //使用cmp的方法速度更快
    //priority_queue<int ,vector<int>,cmp > q;
    long long int n;
    cin>>n;
    for(long long int i=0;i<n;i++)
    {
        cin>>type;
        if(type==1)
        {
            cin>>num;
            q.push(num);
        }
        else
        {
            cout<<q.top()<<endl;
            q.pop();
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值