L2-012 关于堆的判断 - 小顶堆(详解)

将一系列给定数字顺序插入一个初始为空的小顶堆H[]。随后判断一系列相关命题是否为真。命题分下列几种:

  • x is the rootx是根结点;
  • x and y are siblingsxy是兄弟结点;
  • x is the parent of yxy的父结点;
  • x is a child of yxy的一个子结点。

输入格式:

每组测试第1行包含2个正整数N(≤ 1000)和M(≤ 20),分别是插入元素的个数、以及需要判断的命题数。下一行给出区间[−10000,10000]内的N个要被插入一个初始为空的小顶堆的整数。之后M行,每行给出一个命题。题目保证命题中的结点键值都是存在的。

输出格式:

对输入的每个命题,如果其为真,则在一行中输出T,否则输出F

输入样例:

5 4
46 23 26 24 10
24 is the root
26 and 23 are siblings
46 is the parent of 23
23 is a child of 10

输出样例:

F
T
F
T

思路:

先来一波概念~

小顶堆:是一种经过排序的完全二叉树(树的节点是按从上到下,从左到右的顺序紧凑排列的),其中任一非终端节点的数据值均不大于其左子节点和右子节点的值。

heap[i]:=位置i存的元素值。

若从heap[0]开始存,可知:

左儿子编号是自己编号*2+1

右儿子编号是自己编号*2+2

  •  小顶堆插入数据时:

首先先在堆的末尾(在最后一层,最左边)插入该数值,然后不断向上提升至到它比父节点大为止。

  •  小顶堆删除最小值时:

先把堆中最后一个元素复制到根节点,并且删除最后一个节点。然后不断向下交换直到没有大小点到为止。

若向下交换的时候,左右节点都小于此节点,则交换最小的节点。

模板:

void push(int x){
    int i=sz++;
    while(i>0){
        int p=(i-1)/2;
        if(heap[p]<=x)break;
        heap[i]=heap[p];
        i=p;
    }
    heap[i]=x;
}

int pop(){
    int ret=heap[0];
    int x=heap[--sz];
    int i=0;
    while(i*2+1<sz){//点i位置存在左子树即可,因为可能本来就不存在右子树
        int c1=i*2+1,c2=i*2+2;
        if(c2<sz&&heap[c1]>heap[c2])c1=c2;
        if(heap[c1]>=x)break;
        heap[i]=heap[c1];
        i=c1;
    }
    heap[i]=x;
    return ret;
}

ps:处理的时候,别忘了还有负数的情况哒~

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=1005,N1=5005,mod=32767;
int heap[N],sz=0;
string s;
map<int,int>pos;

void push(int x){
    int i=sz++;
    while(i>0){
        int p=(i-1)/2;
        if(heap[p]<=x)break;
        heap[i]=heap[p];
        i=p;
    }
    heap[i]=x;
}

int getx(int po){
    int x=0;
    int tmp=1;
    while(s[po]!=' '&&s[po]!='-'&&po>=0){
        x+=(s[po]-'0')*tmp;
        tmp*=10;
        po--;
    }
    if(s[po]=='-')return -x;
    return x;
}

int solve(){
    int flag,len=s.length(),x=0,y=0;
    for(int i=0;i<len;i++){
        if(s[i]==' '){
            x=getx(i-1);
            if(s[i+1]=='a'){
                flag=2;
                y=getx(len-14);
            }
            else if(i+11==len-1)flag=1;
            else if(s[i+4]=='t'){flag=3;y=getx(len-1);}
            else if(s[i+4]=='a'){flag=4;y=getx(len-1);}
            break;
        }
    }
    if(flag==1){
        if(heap[0]==x)return true;
        else return false;
    }
    if(flag==2){
        int p1=pos[x],p2=pos[y];
        if(p1>p2)swap(p1,p2);
        if(p1%2&&p2-p1==1)return true;
        else return false;
    }
    if(flag==3){
        int p1=pos[x],p2=pos[y];
        if((p2-1)/2==p1)return true;
        else return false;
    }
    if(flag==4){
        int p1=pos[x],p2=pos[y];
        if((p1-1)/2==p2)return true;
        else return false;
    }
}

int main(){
    int n,m,t,x,y;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&t);
        push(t);
    }
    for(int i=0;i<n;i++){
        int x=heap[i];
        pos.insert(pair<int,int>(x,i));
    }
    getchar();
    while(m--){
        getline(cin,s);
        int ans=solve();
        if(ans)printf("T\n");
        else printf("F\n");
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值