锦标赛排序学习笔记

前言

本来也不用写的,是碰到排序题发现根本不会快排才学了一下锦标赛排序的啊。

介绍

锦标赛排序可以用这个等式来描述:

锦标赛排序 = ( 选择排序 + 堆排序 ) 2 \small\textsf{锦标赛排序}=\dfrac{\left(\small\textsf{选择排序}+\small\textsf{堆排序}\right)}{2} 锦标赛排序=2(选择排序+堆排序)

就是这样的,锦标赛排序本质上就是维护一个小根堆(锦标赛排序树),每次取走最小值,而且较堆排序更易于实现。

实现

首先,设原数组为 a a a,锦标赛排序树为 tr \text{tr} tr,还有一棵树 id \text{id} id,排序完的数组为 b b b

这里我们用数组存储树,所以 tr \text{tr} tr id \text{id} id 也是数组,其中对于所有整数 i ∈ [ 1 , n ] i\in[1,n] i[1,n],都有 tr i + n − 1 = a i , i d i + n − 1 = i \text{tr}_{i+n-1}=a_i,id_{i+n-1}=i tri+n1=ai,idi+n1=i。也就是说, tr \text{tr} tr 的第 n n n 层的元素全等于 a a a 中的所有元素。

tr \text{tr} tr 中,任意两个兄弟节点的父节点是他们的最小值,所以在开始时 tr 1 = min ⁡ a \text{tr}_1=\min{a} tr1=mina,同时可以发现:对于所有整数 i ∈ [ 1 , 2 n − 1 ] i\in[1,2n-1] i[1,2n1] tr i ∈ a \text{tr}_i\in a tria,可以发现,此时锦标赛排序树满足小根堆的性质,大致长这样(图片来自 oi-wiki):

图片来自 oi-wiki

可以理解为有 n n n 个人在打淘汰赛,经过 log ⁡ n \log n logn 场比赛后就会产生出冠军,上图中黑线表示被淘汰。

根据选择排序的规则,我们找到了 a a a 的最小值后,就应当删掉它去找次小值,在锦标赛排序中也一样。我们要找到最小值的位置,然后把最小值改成 ∞ \infty ,此时可以像堆一样进行向上调整,调整后的树是这样的:

也就是说,我们在 Θ ( log ⁡ n ) \Theta(\log n) Θ(logn) 的时间里,就找到了次小数!以此类推,最坏情况下完成排序的时间复杂度为 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn)

但这个时候有个问题,我们怎么确定最小值的位置?我们可以用另一棵树 id \text{id} id,它标记了锦标赛排序树上每个节点在 a a a 中的位置,用上面的图举个例子,我们用下标表示 id \text{id} id

大家现在都懂了吧?让我们放代码:

#include <bits/stdc++.h>
#define one(x) ((int)(1e##x))
using namespace std;

int n;
int tr[one(6)];
int id[one(6)];

int main() {
    cin>>n;
    for(int i=1; i<=n; i++) {
        cin>>tr[i+n-1];
        id[i+n-1]=i;
    }
    for(int i=2*n-1; i>1; i-=2) {
        int j=i-1;
        int next=i/2;
        if(tr[i]<=tr[j]) {
            tr[next]=tr[i];
            id[next]=id[i];
        }else {
            tr[next]=tr[j];
            id[next]=id[j];
        }
    }
    for(int i=1; i<=n; i++) {
        cout<<tr[1]<<" \n"[i==n];
        tr[id[1]+n-1]=1000000020;
        int now=id[1]+n-1;
        while(now>1) {
            int j=now^1;
            int next=now>>1;
            if(tr[now]<=tr[j]) {
                tr[next]=tr[now];
                id[next]=id[now];
            }else {
                tr[next]=tr[j];
                id[next]=id[j];
            }
            now=next;
        }
    }
    return 0;
}

复杂度分析

上面已经提到过了:锦标赛排序的时间复杂度最好和最坏均为 Θ ( n log ⁡ n ) + Θ ( n ) \Theta(n\log n)+\Theta(n) Θ(nlogn)+Θ(n),显然优于归并排序。空间复杂度为 Θ ( n ) \Theta(n) Θ(n),常数为 5 5 5

参考文献(撒花)

锦标赛排序 - OI Wiki

树形选择排序(锦标赛排序)_锦标赛排序是稳定的排序方法吗-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值