堆排序

/*2019-7-4-13:56----------------------------woc,我之前写的都是些什么玩意。。--------------------------------------------------------------*/

所谓堆(二叉,这里指的是二叉堆)这个东西,可以O(1)取出最大或者最小值,O(log(n))得删除

插入删除取最值
O(log(n))O(log(n))O(1)

 

 

 

也就是说,这个数据结构可以用来维护一个最值问题

以下是一个大根堆的例子

我们拿数组作为一个完全二叉树来储存堆

1、插入

就是,放到数组最后,然后堆调整上去(一路上和他的父亲比较)

(图是一个大根堆的图,来源、,下面图同样来源)

2、删除

就是把最后一个元素赋值给堆顶,然后堆调整下去(一路上和他的两个儿子比较,每次和最大的儿子交换)

 

 

下面是一份小根堆的代码

int tot = 1;//
void Insert(int data,int pos = tot+1){
    tree[++tot] = data;
    while(tot!=1 && tree[tot]<tree[tot>>1])
        swap(tree[tot],tree[tot>>1]),pos>>=1;
}
void del(int pos = 1){//
    tree[1] = tree[tot--];
    while(true){
        int tpos = pos;
        if((pos<<1)<=tot && tree[tpos]>tree[pos<<1])tpos = pos<<1;
        if((pos<<1|1)<=tot && tree[tpos]>tree[pos<<1|1])tpos = pos<<1|1;
        if(pos == tpos)break;
        swap(tree[pos],tree[tpos]),pos=tpos;
    }
}
int Top(){
    return tree[1];
}

 

对于堆排序就是,先把大根堆建起来,然后每次取出堆顶(最大值),删掉(然后放到数组最后)

最后堆为空,数组有序

时间复杂度分析

建堆O(n*log(n))

取堆顶nO(n)次,删除O(n)次,共O(n*log(n))

综合起来O(n*log(n))

空间复杂度,用的是原来的数组,并没有额外开数组

O(n)

时间空间
O(n*log(n))

O(n)

 

这是一份洛谷p1177快速排序的代码

实测挺快的,也就比我用c++的sort稍微慢一点,比我手写的combsort和shellsort快,但是比Mergesort慢一丁点

也就几ms的差距,他们几个差距不是很大

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int heap[maxn],tot,n;
void Insert(int data,int pos = tot+1){//small heap
    heap[++tot] = data;
    while(pos!=1 && heap[pos]<heap[pos>>1])
        swap(heap[pos],heap[pos>>1]),pos>>=1;
}
void del(int pos = 1){
    if(!tot)return;
    heap[1] = heap[tot--];
    while(true){
        int Next = pos;
        if((pos<<1)<=tot && heap[Next]>heap[pos<<1])Next = pos<<1;
        if((pos<<1|1)<=tot && heap[Next]>heap[pos<<1|1])Next = pos<<1|1;
        if(Next == pos)break;
        swap(heap[pos],heap[Next]),pos = Next;
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1,x;i<=n;i++)scanf("%d",&x),Insert(x);
    for(int i=1;i<=n;i++,del())printf("%d%c",heap[1],i==n?'\n':' ');
    return 0;
}

 

 

/*---------------------------------------------------------分-------------割-------------线-------------------------------------------------------------------------*/

所谓的堆就是一颗完全二叉树,

满足

1对root节点都大于等于(小于等于)其左右子节点

2对其每个子树,都是一个堆(也就是递归定义了呗)

 

其实就是任取一个点,这个点都满足---大于等于(小于等于)其左右子节点(如果有的话)

 

那么根据完全二叉树性质i的左子节点是2*i,右节点是2*i+1,那么就可以在数组里进行操作了(*)

 

将一个数组看成一颗完全二叉树,注意这里应该舍弃0节点,因为其不符合(*)

 

不妨建立大根堆

先建立一个大根堆,那么取出其根节点,与数组中最后一个(假设叫t好了)交换,

相当于删除了大根堆中的根节点,

看怎么调整,让剩下的仍为大根堆,

首先将t放到根节点位置,然后下调,

也就是将左右子节点中大的那个,提上来(与t交换)

递归向下,直到叶子(或者t不能下移,即t放到了他应该在的位置),

这一步log级别(树的高度),每一步取出当前堆中根,也就是最大元素,放到数组末尾,

当取完所有元素,排序即完成

复杂度n*log(n)

 

但是我们一般用的数组都是从0开始的,所以,重新找规律,

i的左子节点等于2*i+1,右:2*i+2(左+1)

 

 

void swap(int &a,int &b){
    int c = a;
    a = b,b = c;
}
void heapcr(int *a,int rt,int mx){
    int l = rt<<1|1,maxid = rt;
    int r = l+1;
    if(l<mx && a[l]>a[rt])
        maxid = l;
    if(r<mx && a[maxid]<a[r])
        maxid = r;
    if(maxid != rt){
        swap(a[rt],a[maxid]);
        heapcr(a,maxid,mx);
    }
}
void Heapsort(int *a,int len){
    for(int i=len/2-1;i+1;i--)
        heapcr(a,i,len);
    for(int i=len-1;i;i--){
        swap(a[0],a[i]);
        heapcr(a,0,i);
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值