[OI学习笔记]堆&堆排序

今天学历配对堆,然鹅我把普通的堆忘了,配对堆也听得云里雾里。。。现在自己来现场yy一下

手写堆

push就把元素放到最后面,不断把他和父亲比较,上浮

pop就把堆顶和最后一个元素交换,然后对交换后的堆顶不断和他的左右儿子比较(选左右儿子中优先级高的比),下沉,最大下沉到最后一个元素下标-1的位置,然后元素总数-1

代码:(大根堆)

#include<cstdio>
#include<algorithm>
using namespace std;
#define lson(x) (x<<1)
#define rson(x) ((x<<1)+1) 
#define fat(x) (x>>1)

int tot=0,a[100010];

void swap(int &a,int &b){
    if(&a==&b)return;
    a^=b^=a^=b;
}

void putdown(int x,int m){//下沉的点的下标&最大下沉下标 
    int l=lson(x),r=rson(x),tag;
    if(l>m)return;
    if(r<=m&&a[r]>a[l])tag=r;
    else tag=l;           //找到左右儿子中最[大]的来替换
    if(a[x]<a[tag])swap(a[x],a[tag]);
    putdown(tag,m);//继续下沉
}

void putup(int x){
    int fa=fat(x);
    if(fa<1)return;
    if(a[x]>a[fa])swap(a[x],a[fa]);
    putup(fa);
}

void push(int num){
    a[++tot]=num;
    putup(tot);
}

void pop(){
    swap(a[1],a[tot]);
    printf("你刚刚干掉了堆顶,他的值为%d
",a[tot]);
    --tot;
    putdown(1,tot);
}

//大根堆 
int t;
int main(){
    scanf("%d",&t);
    printf("input “1”for push,or input “0” for pop。");
    for(int i=1;i<=t;i++){
        int ques;
        scanf("%d",&ques);
        if(ques){
            int kkk;
            scanf("%d",&kkk);
            push(kkk);
        }else
            pop();
    }
    return 0;
} 

堆排序

知道堆的运作原理,实现堆排序就很简单了,注意假如你是大根堆,要求从小到大排列,输出时要反过来(因为每次pop都把最大的搞到当前的最后)

下面是吧序列从大到小排:

#include<cstdio>
#include<algorithm>
using namespace std;
#define lson(x) (x<<1)
#define rson(x) ((x<<1)+1) 

int n,a[100010];

void swap(int &a,int &b){
    a^=b^=a^=b;
}

void update(int x,int m){//下沉的点的下标&最大下沉下标 
    int l=lson(x),r=rson(x),tag;
    if(l>m)return;
    if(r<=m&&a[r]>a[l])tag=r;
    else tag=l;           //找到左右儿子中最[大]的来替换
    if(a[x]<a[tag])swap(a[x],a[tag]);
    update(tag,m);//继续下沉
}

void heap_sort(){
    for(int i=n;i>=1;i--)update(i,n);//建堆 
    for(int i=n-1;i>=1;i--){
        swap(a[i+1],a[1]);//交换对顶和最后一个节点,相当于pop
        update(1,i);//注意这里最大下沉到i(防止堆顶不再浮上来) 
    }
}

//大根堆 
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    heap_sort();
    for(int i=n;i>=1;i--)//反着输出 
        printf("%d ",a[i]);    
    return 0;
} 
本篇文章为SHINE_GEEK原创,转载请注明来源!
written_by:SHINE_GEEK

-------------------------------------
签名:自己选的路,跪着也要走完;理想的实现,需要不懈奋斗!
-------------------------------------
原文地址:https://www.cnblogs.com/sjrb/p/10371613.html