C++ P3378 【模板】堆

版权声明:转载请保留原地址 https://blog.csdn.net/u012972031/article/details/82809523

先看了一下《算法》,大概懂了基本原理之后,先抄了一遍题解,然后做了一遍。做的时候发现了几处错误,第五次的时候成功AC

代码:

#include<cstdio>
#include<iostream>
#include<cctype>
using namespace std;
int heap[50001];
int heap_size=0;
inline int readint(){
    char c=getchar();
    while(!isdigit(c)){
        c=getchar();
    }
    int n=0;
    while(isdigit(c)){
        n=n*10+c-'0';
        c=getchar();
    }
    return n;
}
void put(int a){
    int now,next;
    heap[++heap_size]=a;
    now=heap_size;
    while(now>1){
        next=now/2;
        if(heap[now]>=heap[next])return;
        swap(heap[now],heap[next]);
        now=next;
    }
}
void del(){
    int now,next;
    heap[1]=heap[heap_size--];//heap[1]=0;swap(heap[1],heap[heap_size]);
    now=1;
    while(now*2<=heap_size){//注意:这里应该是 now*2<=heap_size 而不是next<heap_size 或 next<=heap_size 
        next=now*2;
        if(heap[next+1]<heap[next])next++;//if(heap[next]<heap[next+1])next++;
        if(heap[next]>=heap[now])return;
        swap(heap[next],heap[now]);
        now=next;
    }
}
int get(){
    return heap[1];
}
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        int input;
        input=readint();
        //cout<<"INPUT: "<<input;
        if(input==1){
            int input2;
            input2=readint();
            //cout<<"read 2";
            put(input2);
        }else if(input==2){
            cout<<get()<<endl;
        }else if(input==3){
            del();
        }
    }
}

小根堆:
在这里插入图片描述

1.插入
假设你已经有一个堆了,就是上面那个

这个时候你如果想要给它加入一个节点怎么办,比如说0?

先插到堆底(严格意义上来说其实0是在5的左儿子的,图没画好放不下去,不过也不影响)

然后你会发现它比它的父亲小啊,那怎么办?不符合小根堆的性质了啊,那就交换一下他们的位置
在这里插入图片描述

交换之后还是发现不符合小根堆的性质,那么再换
在这里插入图片描述
还是不行,再换

在这里插入图片描述

好了,这下就符合小根堆的性质了,是不是顺眼很多了?(假的,图越来越丑,原谅我不想再画)

上浮4.png

事实上堆的插入就是把新的元素放到堆底,然后检查它是否符合堆的性质,如果符合就丢在那里了,如果不符合,那就和它的父亲交换一下,一直交换交换交换,直到符合堆的性质,那么就插入完成了

2.删除
把0插入完以后,忽然你看这个0不爽了,本来都是正整数,怎么就混进来你这个0?

于是这时候你就想把它删除掉

怎么删除?在删除的过程中还是要维护小根堆的性质

如果你直接删掉了,那就没有堆顶了,这个堆就直接乱了,所以我们要保证删除后这一整个堆还是个完好的小根堆

上浮4.png

首先在它的两个儿子里面,找一个比较小的,和它交换一下,但是还是没法删除,因为下方还有节点,那就继续交换

上浮3.png

还是不行,再换

上浮2.png

再换
在这里插入图片描述

好了,这个碍眼的东西终于的下面终于没有节点了,这时候直接把它扔掉就好了

在这里插入图片描述

这样我们就完成了删除操作,但是在实际的代码操作中,并不是这样进行删除操作的,有一定的微调,代码中是直接把堆顶和堆底交换一下,然后把交换后的堆顶不断与它的子节点交换,直到这个堆重新符合堆性质(但是上面的方式好理解啊)

(以上内容出自这里
题目地址:https://www.luogu.org/problemnew/show/P3378

猜你喜欢

转载自blog.csdn.net/u012972031/article/details/82809523