ds排序--希尔排序_排序--快速排序

相信我们在没接触过排序知识之前,一定会觉得快速排序非常具有魅力,不因别的单纯快排这个名字就让人不明觉厉,但是了解一个算法不应该只知道code,了解思想,应用非常重要。

我先问出我心中非常好奇的问题:

  1. 快排为啥叫快排,快排是所有排序里面性能最好的吗?
  2. 快排适合什么情况呢,还是无论什么情况下快排总是最好的(显然× ?
  3. 快排算法的思想是什么?其性能优良的原因是依赖于算法中的哪个部分?

首先回答前两个问题:

快排的性能在所有排序算法里面是最好的,数据规模越大快速排序的性能越优。快排在极端情况下会退化成

equation?tex=O%28n%5E%7B2%7D%29 的算法,因此
假如在提前得知处理数据可能会出现极端情况的前提下,可以选择使用较为稳定的归并排序。

下面回答第三个问题:

  • Quick Sort

e270f20f7a56f2c11c02393211c4d81f.gif
一次快排过程

显然,我们从图中可以看出快排运用了二分的思想,首先选择一个基准,定义左右两端指针,先从左到右进行扫描直到,R[hi] < temp,将R[hi]移动至lo所在位置

equation?tex=%5CRightarrow 从右往左进行扫描,直到R[lo] > temp,将R[lo]移动到hi所在位置上,左右端指针在排序过程中从数组的两端往中间进行靠近,直到hi == lo。而快速排序则要进行多次快排过程,直到划分的区间最后长度仅为1.

总结下来(转, 自己懒得敲了:

  • 选择A中的任意一个元素pivot,该元素作为基准
  • 将小于基准的元素移到左边,大于基准的元素移到右边(分区操作)
  • A被pivot分为两部分,继续对剩下的两部分做同样的处理
  • 直到所有子集元素不再需要进行上述步骤
void QuickSort(R[], int lo, int hi)
{
    将lo, hi用i, j两个副本进行拷贝(**
    声明基准;
    if(划分长度大于等于2,即hi > lo)
    {
        取基准为左端端点;//都可
        当hi 不等于 lo时循环;
            当hi > lo且R[hi] > temp时循环;
                hi--(继续往中间靠;
            R[lo] = R[hi];//发现小于基准的替换将其替换到左半区
            当lo < hi且R[lo] < temp时循环;
                lo++(继续往中间靠;
            R[hi] = R[lo];//发现大于基准的将其替换到右半区
        在hi,lo重合处放基准;//数据平衡,循环里有一个数据是直接被覆盖的,就是基准,现在将其添加回数组中
        QuickSort(R[], lo, i - 1);
        QuickSort(R[], i + 1, hi);//递归继续进行快排
        //要是前面没有进行副本拷贝在这里进行递归操作时就不太好判断边界了。
    }
}

equation?tex=Q%3A+ 请写出快速排序的真正代码(见文末)

现在回答一下,为什么快速排序是平均性能最好的排序算法,其优渥之处体现在哪?

  • 首先,如果我们已经知道
    equation?tex=a%3Cb ,那么之后
    equation?tex=a%2C%5C%3B+b 就无需再比较了,假如再进行比较就是
    重复在快排中其中有一个一定是基准,因此假如进行一次比较之后就不会再次进行比较了。
  • 第二,假如我们已知,
    equation?tex=a%3Cb%3Cc ,那么
    equation?tex=a%2C%5C%3Bc 就不需要进行比较了,再进行比较就算是
    冗余,而在快排中这种情况是不会发生的,因为
    equation?tex=b 就是递归排序的基准,因此
    equation?tex=a%2C%5C%3Bc 就只会在自己的区间进行排序,不会出现冗余排序了。

因此,我们可以了解到,快速排序的优越性体现在他没有多余的比较上,对于初学者,我们可以较为简单的认为,快排所需要的指令数会比较少。

算法分析

  • 最差情况:

最差情况是,每次我们在划分时,所取的基准总是数组中最小的,因此我们总共会进行

equation?tex=n-1 次划分,且在第
equation?tex=i 次划分时,区间长度为:
equation?tex=n+-+i%2B1 ,需要进行
equation?tex=n-i 比较。

故:

equation?tex=C_%7Bmax%7D%3D%5Csum_%7Bi+%3D1%7D%5E%7Bn-1%7D%7Bn-i%7D%3D%5Cfrac%7Bn%28n-1%29%7D%7B2%7D%3DO%28n%5E%7B2%7D%29
  • 最好情况:

最好的情况是,每次所取的基准就是该数组的中点,因此一共需要进行n次划分,对于 长度为

equation?tex=n 的划分空间,需要进行
equation?tex=n-1 次比较。剩下的两个无序子区间需要进行
equation?tex=2C%28%5Cfrac%7Bn%7D%7B2%7D%29 的比较次数。设
equation?tex=n+%3D+2%5E%7Bk%7D 故:

equation?tex=C%28n%29%5Cleq+n%2B2C%28%5Cfrac%7Bn%7D%7B2%7D%29

equation?tex=%5Cleq+n%2B2%28%5Cfrac%7Bn%7D%7B2%7D%2B2C%28%5Cfrac%7Bn%7D%7B2%5E%7B2%7D%7D%29%29%3D2n%2B4C%28%5Cfrac%7Bn%7D%7B2%5E%7B2%7D%7D%29

equation?tex=%5Cleq+kn%2BnC%281%29+%3D+%5Cleq+n%5C%3Blog_%7B2%7Dn%5C%3B%2B%5C%3BnC%281%29%3DO%28nlog_%7B2%7Dn%29
  • 平均情况:

用递归算(下次补。。。):

随机进行切割,最好算出复杂度还是

equation?tex=O%28nlog_%7B2%7Dn%29
void QuickSort(int R[], int lo, int hi){
    int i = lo, j = hi;
    int temp;
    if(i < j){
        temp = R[i];
        while (i != j)
        {
            while(j > i && R[j] > temp)-- j;
            R[i] = R[j];
            while(i < j && R[i] < temp)++ i;
            R[j] = R[i];
        }
        R[i] = temp;
        QuickSort(R, lo, i - 1);
        QuickSort(R, i + 1, hi);
    }
}

equation?tex=Talk%5C%3Bis%5C%3B+easy%2C%5C%3Bshow%5C%3Bme%5C%3Bthe%5C%3Bcode.%5Cquad+XD
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值