基础排序算法总结

下面总结一些常见的高效的排序算法。

1. 归并排序

  • 主要思想:递归排序+合并。
  • 复杂度:O(NlogN)。好写速度快,不容易卡。
int a[10]={0,2,9,1,7,8,5,3,4,2},T[10];

void Msort(const int L,const int R)
{
    if (R-L<=1) {if (a[L]>a[R]) swap(a[L],a[R]); return;}
    //两个数时可以直接比较
    Msort(L,(L+R)>>1); Msort(((L+R)>>1)+1,R);//递归排序
    x=L; y=((L+R)>>1)+1; p=0;//初始化指针(用普通整数模拟,指针应该更快)
    while (x<=((L+R)>>1)&&y<=R)
        if (a[x]<a[y]) T[++p]=a[x++];
        else T[++p]=a[y++];
    while (x<=((L+R)>>1)) T[++p]=a[x++];
    while (y<=R) T[++p]=a[y++];
    for (register int i=1; i<=p; i++)
        a[i-1+L]=T[i];//数组还原
}
Msort(1,N);

2. 快速排序

  • 主要思想:找基准数+递归排序
  • 复杂度:O(NlogN),稍微难写,容易卡(如果快排能过当然都用sort了),没有归并实用。
void Qsort(const int L,const int R)
{
    if (R-L<=1) {if (a[L]>a[R]) swap(a[L],a[R]); return;}
    x=L; y=R; k=a[L];
    while (x<y)
    {
        while (a[y]>=k&&x<y) y--; a[x]=a[y];
        while (a[x]<=k&&x<y) x++; a[y]=a[x];
    }
    a[x]=k; Qsort(L,x); Qsort(x+1,R);
}
Qsort(1,N);

3. 基数排序

  • 主要思想:二进制划分数 & 桶排序扩展
  • 复杂度:O(kN),不过据说int划成4段要比两段快,看机型吧。浮点基排本蒟蒻不会。高端大气且效率较高,代码量也不大,但是只能排整数。
void Rsort()
{
    //这里是int划分为两段的低位向高位排序,从高到低的话效率应该差不多。
    register int i=0;
    for (i=1; i<=N; i++) T[(a[i]&0xffff)+1]++;
    for (i=1; i<=0xffff; i++) T[i]+=T[i-1]; 
    for (i=1; i<=N; i++) b[++T[(a[i]&0xffff)]]=a[i];//先按照后16位划分重排
    memset(T,0,sizeof(T));
    for (i=1; i<=N; i++) T[(b[i]>>16)+1]++;
    for (i=1; i<=0xffff; i++) T[i]+=T[i-1];
    for (i=1; i<=N; i++) a[++T[(b[i]>>16)]]=b[i];//再按照前16位划分重排。
}

基数排序的虽是O(N)常数却大,比sort相比优势并不明显。

4. 总结

  1. 排序方法虽多,一般都用sort,但是为什么要学归并呢?因为对于每次只有小改动的序列,复杂度相同的归并就比快排强了许多,所以有些题是可以卡sort的。例子:P1309 瑞士轮

  2. 考试做题时,不一定动不动就要sort,如果你发现桶排或者基排可以实现要求的排序相信你一定会很高兴。许多题的瓶颈正是在排序上(比如很多离线算法,还有Kruskal)

posted @ 2019-01-05 15:48  Ofnoname  阅读(65)  评论(0编辑  收藏  举报