九种排序算法

复习一下排序




1. 计数排序

这算是最早学的排序了.
复杂度最低,但是没什么卵用.
排序范围十分有限,且只能排数.

for (int i=1;i<=n;++i){
    cnt[num[i]]++;//统计次数
}
for (int i=0;i<M;++i) {
    for (int j=1;j<=cnt[i];++j) cout<<i<<" ";
}
puts("");

稳定排序,时间复杂度O(n+m),O(n+m)$


2. 选择排序

相比计数排序,排序范围大了很多,但是复杂度变为了O(n2).

for (int i=1;i<=n;++i) {
    int id=i;
    for (int j=i+1;j<=n;++j) {
        if (num[j]<num[id]) id=j;//选择一个最小的
    }
    swap(num[i],num[id]);
}

不稳定排序,时间复杂度O(n2)


3. 冒泡排序

就是让大的泡泡向上冒泡的过程
虽然常数大,但是它可以在排序时判断是否已经有序来加快速度.

while (true) {
    bool chk=true;
    for (int i=1;i<n;++i) {
        if (num[i]>num[i+1]) swap(num[i],num[i+1]),chk=false;
    }
    if (chk) break;//有序时退出
}

稳定排序,平均时间复杂度O(n2),最好时间复杂度O(n))


4. 插入排序

把数一个个插入序列中.
插入时把比它大的挪到后面,直到找到一个比他小的.
(同为n2,但是插入排序的常数比冒泡小)

for (int i=1;i<=n;++i) {
    int x=num[i];
    for (int j=i-1;j&&x<num[j];--j) num[j+1]=num[j];//向后移动
    num[j+1]=x;
}

稳定排序,平均时间复杂度O(n2),最好时间复杂度O(n))


5. 基数排序

升级版计数排序,但是还是只能排数.

int num[M]
int s[10][M],len[M]={0};
for (int sz=1;;) {
    bool chk=false;
    for (int i=1;i<=n;++i) {
        chk|=num[i]/sz;
        int k=num[i]/sz%10;
        s[k][len[k]++]=num[i];
    }
    if (!chk) break;
    int id=0;
    for (int i=0;i<10;++i) {
        for (int j=0;j<len[i];++j) {
            num[++id]=s[i][j];
        }
        len[i]=0;
    }
    sz*=10;
}

稳定排序,时间复杂度O(nm),m为长度.


6. 归并排序

复杂度稳定的O(nlogn)排序,
用了分治的思想,把一个问题分解为小规模的子问题,
直到子问题可以直接解决,再把子问题合并解决大问题.

merge(int L,int R) {
    if (L==R) return;
    int mid=(L+R)>>1;
    merge(L,mid),merge(mid+1,R);
    int i=L,j=mid+1;
    int tot=0;
    while (i<=mid&&j<=R) {
        if (num[i]<num[j]) tmp[tot++]=num[i++];
        else tmp[tot++]=num[j++];
    }
    while (i<=mid) tmp[tot++]=num[i++];
    while (j<=R) tmp[tot++]=num[j++];
    for (int i=0;i<tot;++i) num[i+L]=tmp[i];
}

稳定排序,时间复杂度O(nlogn),O(n),可用来统计逆序对个数$


7. 快速排序

非常重要的排序.
基本思想是:
1. 选一个中轴.
2. 把数组劈成两半,左边比中轴小,右边比中轴大.
3. 递归处理两边.

template <class T> void Sort(T *st,T *ed) {
    T k=*st;
    T *L=st,*R=ed;
    while (L<R) {
        while (L<R&&*R>=k) R--;
        if (L<R) *L=*R;
        while (L<R&&*L<=k) L++;
        if (L<R) *R=*L;
    }
    *L=k;
    if (st<L-1) Sort(st,L-1);
    if (L+1<ed) Sort(L+1,ed);
}

当然这只是最裸的快速排序,复杂度最高可达到O(n2),快速排序是有很多优化的.
不稳定排序,平均时间复杂度O(nlogn),最坏时间复杂度O(n2),可用来求第k大值


8. 希尔排序

感觉没什么用.


9. 堆排序

优化了的选择排序.
虽然常数大,但是它可以维护序列顺序,这是其他排序做不到的.

template <class T,int M,bool (*f)(int &A,int &B)>
struct heap {
    T num[M<<2];
    int tot;
    void up(int p) {
        while (p!=1) {
            if (f(num[p],num[p>>1])) {
                swap(num[p],num[p>>1]);
                p>>=1;
            } else break;
        }
    }
    void down() {
        int p=1;
        while ((p<<1)<=tot) {
            int to=p<<1;
            if (to+1<=tot&&f(num[to+1],num[to])) to++;
            if (f(num[to],num[p])) swap(num[p],num[to]),p=to;
            else break;
        }
    }
    bool empty() {
        return tot;
    }
    T top() {
        return num[1];
    }
    void push(int x) {
        num[++tot]=x;
        up(tot);
    }
    void pop() {
        num[1]=num[tot--];
        down();
    }
};

不稳定排序,时间复杂度O(nlogn)

希尔还没写,留着以后填吧.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值