堆和堆排序

  1. 这个题大意是有一个数据结构支持两种操作AGet操作,其中A x表示插入x. Get i表示返回结构中的第i小的数.给你AGet操作的顺序和参数,现在要你对每个Get输出值.
  • 取前u(i)个数排序~
  • 然后取第i个数~(i=1,2,3……)
  • 后来发现可以用大顶堆和小顶堆做~
  • 每次将u(i)个数存入小顶堆中~
  • 取小顶堆堆顶元素存入大顶堆中~
  • 删除堆顶元素~
  • 将大顶堆堆顶元素存入小顶堆中删除堆定元素~
  • 这样大顶堆中的元素个数不变~
  • 总是最小的前i个~

题解:每次取第k小元素,k不断更新。使用两个堆,来完成。 小顶堆负责选出最小的元素,大顶堆负责选出k个元素中最大的元素,即第k小元素 

大顶堆的堆顶元素始终小于小顶堆的堆顶元素,这样的话大顶堆中的所有元素都小于小顶堆中的元素,如果大顶堆中有k-1个元素,那么小顶堆的堆顶元素就是要找的 第k小 元素了

Sample Input
7 4                                         ( n,m,分别是a数组,u数组的元素个数)

3 1 -4 2 8 -1000 2               (a数组)
1 2 6 6  (
数u[i]w为几就加到a几,然后输出第i 小的:输出数组a前1个第1小的,前两个第2小的,前6个第3小的,前6个第4小的)


Sample Output
3
3
1
2

  • 大根堆分别有1、2、3、4个元素   3 ,3   1,3  1 -4 2 8 -1000,3 1 -4 2 8 -1000。。。。3,3 1,1 -4 -1000,1 -4 2 -1000。。。。_,1, -4 -1000,1 -4  -1000
  • 小顶堆元素为 3,3,3 1 2 8,3 2 8  即负责选出最小元素

#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;

const int maxint=30010;

int num[maxint];
int query[maxint];

priority_queue<int ,vector <int> ,less<int> >p2;//大根堆
priority_queue<int ,vector <int> ,greater<int> >p1;//小根堆

int main()
{
 int m,n,i,j,k;
 int temp;
 while(scanf("%d%d",&m,&n)!=EOF)
 {
  for(i=0;i<m;i++)
   scanf("%d",&num[i]);
  for(i=0;i<n;i++)
   scanf("%d",&query[i]);
  //输入结束之后,就是从头到尾维护一个大根堆和小根堆
  //大根堆中始终存放在查询之前的元素
  j=0;
  for(i=0;i<m;i++)
  {
   p2.push(num[i]);//把第i个元素放入大根堆
   p1.push(p2.top());//把大根堆的最大元素放入小根堆
   p2.pop();
   if(query[j]==i+1)//当前询问
   {
    while(query[j]==i+1)
    {
     temp=p1.top();//小根堆的最小元素就是第i+1小的元素,因为大根堆中的i个元素
     p1.pop();//都小于temp
     p2.push(temp);
     printf("%d\n",temp);
     j++;
    }
   }
  }
 }
 return 0;
}


题外话丨分治法  直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值