基础算法--堆的结构及其常用操作和排序

堆,是一种完全二叉树的树状结构,分为小根堆与大顶堆。本文论述以及代码实现都是小根堆,大根堆同理。

如上图所示,我们可以看到一个完全二叉树,而每个结点的编号与其左右儿子的关系为(假设某结点的编号为u):left=2*u,right=2*u+1。

堆有如下的操作:

1.建堆

2.向下调整

3.向上调整

4.删除第一个(最小)元素

5.删除任意一个元素

6.插入某个元素

而2,3以后的操作全都可以用2,3两个操作组合完成。

小根堆的表述为:某个结点永远小于等于其左右儿子。那么我们就可以通过向下调整(大的往下沉)或向上(小的往上浮)调整来建立一个堆,代码如下:

void down(int u){//向下调整
    int t=u;
    if(u*2<=n&&h[u*2]<h[t])t=u*2;
    if(u*2+1<=n&&h[u*2+1]<h[t])t=u*2+1;
    if(u!=t){
        swap(h[u],h[t]);
        down(t);
    }
}
void up(int u){//向上调整
    while(u/2&&h[u/2]>h[u]){
        swap(h[u/2],h[u]);
        u/=2;
    }     
}

那么4,5,6的操作依次可以表示为:

h[1]=h[n],n--,down(1);
h[k]=h[n],n--,down(k) or up(k);
h[++n]=k,up(n);

下面是堆排序:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=1000010;
vector<int>h(N),f(N);
int n;

void down(int u, int n){//向下调整
    int t=u;
    if(u*2<=n&&h[u*2]<h[t])t=u*2;
    if(u*2+1<=n&&h[u*2+1]<h[t])t=u*2+1;
    if(u!=t){
        swap(h[u],h[t]);
        down(t,n);
    }
}
void heap_sort(int n){
    for(int i=n/2;i;i--)down(i,n);
    int i=1,k=n;
    while(k){
        f[i++]=h[1];
        h[1]=h[k--];
        down(1, k);
    }
}
int main(void){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>h[i];
    heap_sort(n);
    for(int i=1;i<=n;i++)cout<<f[i]<<' ';
    cout<<endl;
    return 0;
}

 

posted @ 2019-07-13 15:04  YF-1994  阅读(295)  评论(0编辑  收藏  举报