O(nlogn)的一般排序方法

前言

上次介绍了几种最简单常用的排序算法,但对于咱们现在这个时代来说,这些算法已经太慢了,几乎没有实用价值,所以这次说一些比较常用实用的更快的排序算法。
还有就是这些算法有的用到了分治的思想。建议去学习一下这种思想,非常有用。

种类

  1. 希尔排序
  2. 堆排序
  3. 归并排序
  4. 快速排序

希尔排序

关于希尔排序的主要是思想就是跳跃式交换,从而提高了排序的速度,而其跳跃式交换就依赖于其中的一个变量:inc。
我个人认为这是一个非常巧的排序,以至于我不知道这个方法为什么可行(逃···
反正··就是利用这个方法就可以高效的完成排序。

void ShellSort(int *a,int len)
{
    int inc=len;
    while(inc>1)
    {
        inc=inc/3+1;//关于这个运算,有很多种其他的算法方法,不止这一种
        for(int i=inc+1;i<=len;++i){
            if(a[i]<a[i-inc]){
                a[0]=a[i];
                int j;
                for(j=i-inc;j>0&&a[0]<a[j];j-=inc)//跳跃式交换
                    a[j+inc]=a[j];
                a[j+inc]=a[0];//腾出的位置给a[i]
            }
        }
    }
    print(a,len);
}

堆排序:

关于堆的定义这里就不在赘述了,反正大家都知道。
我写的这个堆排序和书上的有些不一样,区别在于每次都从倒数第二层开始进行根节点的调整,而不是从上往下进行调整,我觉得那样过于麻烦,而且也没有比我这个快多少。
并且我这个排序的空间利用率也是O(1)的

void HeapAdJust(int *a,int num)//调整数组,使其符合堆的定义
{
    for(int i=num/2;i>=1;--i){
        if(a[i]<a[i*2])
            Swap(a[i],a[i*2]);
        if(a[i]<a[i*2+1])
            Swap(a[i],a[i*2+1]);
    }
}
void HeapSort(int *a,int n)
{
    int b;
    for(int i=1;i<=n;++i){
        HeapAdJust(a,n-i+1);//注意这块的n-i+1,代表之后的数就不考虑了,认为已经被挪走
        b=a[1];
        a[1]=a[n-i+1];
        a[n-i+1]=minl;//把最小的交换到堆顶
        a[n-i+2]=b;//重要的地方,如果不是+2的话,会因为调整函数不知道这个是已经从堆顶拿走的数据,而导致出现错误,所以整体后移一格
    }
    print(a+1,n);//最后输出也是整体后移一格
}

下面的排序用到了分治的思想

归并排序

就是把一个序列分成两个序列,一直分下去知道序列里只有一个值。然后进行合并,合并时就和两个有序数列的合并一样,没有难度。
其归并的思想在于将一个大序列有序转换成多个小序列有序,分而治之。从而简化问题,当只有一个值时,其答案是显而易见的

void Merge(int *a,int f,int mid,int r,int *b)//区间的合并
{
    int pa1=f,pa2=mid+1,pb=0;
    while(pa1<=mid&&pa2<=r)
    {
        if(a[pa1]<a[pa2])
            b[pb++]=a[pa1++];
        else
            b[pb++]=a[pa2++];
    }
    while(pa1<=mid)
        b[pb++]=a[pa1++];
    while(pa2<=r)
        b[pb++]=a[pa2++];
    for(int i=0;i<pb;++i)
        a[f+i]=b[i];
}

void MergeSort(int *a,int f,int r,int *b)
{
    if(f<r){
        int mid=(f+r)/2;
        MergeSort(a,f,mid,b);//每次分成两个区间
        MergeSort(a,mid+1,r,b);
        Merge(a,f,mid,r,b);
    }
}

快速排序

每次寻找一个key值,然后对区间进行操作。使其在区间中的位置为:在key之前的都比key小,在key之后的都比key大。然后再将这前后两个序列进行上述步骤。
快排所利用的也是分治的思想,将大区间转化为小区间,而每两个小区间的值不存在交叉的问题,所以效率非常的高。

void QuickSort(int *a,int f,int r)
{
    if(f>=r)
        return ;
    int i=f;
    int j=r;
    int k=a[i];
    while(i!=j)//把key值放到合适的位置
    {
        while(i<j&&a[j]>k)
            --j;
        if(i<j)
            Swap(a[i],a[j]);

        while(i<j&&a[i]<k)
            ++i;
        Swap(a[i],a[j]);
    }//a[i]=k
        QuickSort(a,f,i-1);//分成两个区间,分别操作
        QuickSort(a,i+1,r);
}

总结

其实这些排序想明白了也很好理解,并且灵活运用这些算法对将来的很多问题也会有很大的帮助。虽然STL中有现成的sort函数,但自己敲出来的收获肯定是比直接调用STL的收获要大的。
并且这些排序也能告诉我们,想要做出进步,就必须突破原有的思维限制,勇于尝试新的东西。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值