快排原理

快排原理讲解

第一步,理解算法核心

假设你有一堆横排的体重不一的萝卜,你想把它们按照重量从小到大进行排序。

快排思路

准备工作:
0、如果最左边萝卜的下标>=最右右边萝卜下标,结束。(这就是我们的递归出口)
1、把第一个萝卜挖出来备用。
2、找两个工人一个叫A一个叫B,分别站在第一个萝卜(注意第一个萝卜的坑已经空了)和最后一个萝卜的位置。
3、如果A和B相遇了,则执行6,否则继续执行4和5
4、B往左走寻找比挖出来的第一个萝卜轻,且位置在A右边的萝卜,找到了就挖出来放到左所在的空坑里(这时B守着空坑)
5、由于B把A的坑用掉了,所以A要往右寻找比一个萝卜重,且位置在B左边的萝卜,找到了就挖出来放到B守着的空坑里(这时A又守空坑了),执行3
6、这时候两人已经相遇了,我们曾经把第一个萝卜挖出来,所以这时候必定有一个位置是空着的,这个位置也必然是他们相遇的这个位置,为什么呢?因为A和B相遇有两种情况,A往右走,与遇到B和B往左走遇到A,A和B的工作其实就是找到合适的萝卜去填对方的坑,当有一方在走,另一方所在位置必然是空的,所以A遇到B时候B是空的,B遇到A的时候A时是空的,所以最后的空坑肯定是他们相遇的位置。这时候只要把我们挖出的第一个萝卜放入这个空坑,就可以达到一个效果那就是相遇位置放上第一个萝卜之后,它左边的萝卜质量都小于它,它右边位置的萝卜质量都大于它。这时候就执行步骤7。
7、把所有萝卜分成两堆,[第一个萝卜,相遇位置]为第一堆,[相遇位置+1,第最后一个萝卜]为第二堆。对这两堆萝卜从步骤0开始执同样的操作。

注意

这里所谓的挖出萝卜产生空坑是逻辑上的不是物理上的,我们执行a=b之后,逻辑意义是将b存入了a,但是b中的值还是存在的。同理我们把A位置萝卜存入B位置之后A位置的值还是存在的,但是已经没有意义了,可以被别的值覆盖掉,也就是说我在第二步中的X的含义不是这里没有值了,而是这里的值已经拷贝到另一个位置,而这个位置可以被别的值直接覆盖。

第二步,数据模拟

注意:加红的表示A和B当前所在位置
初始萝卜:
5 6 7 3 4
0、左边位置0,右边4,继续执行
1、挖掉5,变成 X 6 7 3 4
2、A站在0,B站在4
3、A和B没有相遇,执行4、5
4、B从所在位置开始往左找发现4比挖掉的5小,且位置在A右边,所以把4放到A的位置,变成4 6 7 3 X
5、A从所在位置往右找,找比第一个萝卜大的萝卜,找到6,将6放到B所在坑位,变成4 X 7 3 6
3、A和B没有相遇继续4、5
4、B从所在位置开始往左找发现3比挖掉的5小,且位置在A右边,所以把3放到A的位置,变成4 3 7 X 6
5、A从所在位置往右找,找到7,将6放到B所在坑位,变成4 3 X 7 6
3、A和B没有相遇,执行4、5
4、B从所在位置开始往左找,发现A的位置和它相等了,而且是个空坑,所以B虚空将该位置并不存在的萝卜放在该位置,这步属于累赘执行。变成4 3 X 7 6
5、A从所在位置开始往右找,发现B的位置和它祥光了,而且是个空坑,所以A也虚空将该位置并不存在的萝卜放在该位置,这步属于累赘执行。变成4 3 X 7 6
3、A已经遇到B执行6
6、将第一次挖出的5放到相遇位置,变成了4 3 5 7 6
7、分成两堆,一堆[0,2],另一堆[3,4]
8、对[0, 2]这堆的萝卜进行步骤0开始的一系列操作,对[3, 4]这堆的萝卜进行步骤0开始的一系列操作。

伪代码

QuickSort(萝卜数组a, 左边位置, 右边位置) {
if (左边位置 >= 右边位置) {
return;//步骤0
}
key = 第一个萝卜重量;//步骤1
将左右两边位置分别存入A、B之中;//步骤2
while (A位置 < B位置) {//步骤3
while (B位置 > A位置 && B位置萝卜质量 >= key)
right–;//步骤4.1
将B位置萝卜放入A所在空位;//步骤4.2
while (left < right && a[left] <= key)
left++;//步骤5.1
a[right] = a[left];//步骤5.2
}
a[left] = key;//步骤6
QuickSort(萝卜数组a, 左边位置, A位置);//步骤7.1
QuickSort(萝卜数组a, A位置+1, 右边位置);//步骤7.2
}

难点

临界情况:
5 3
这组数据的运行情况是这样的:
记录5
B找到3比5小移到A位置变成3 X,
然后A右移遇到B,将B位置数放入A位置(其实就是同意位置放入同一位置)。
A和B已经相遇,跳出while循环,将5放入当前空坑变成3 5。
对[0,1],[2,1]对两段进行递归调用。
第一段:
[0,1],数据为3 5
这组数据运行情况是这样的:
记录3
B找到3位置遇到A,将B位置数放入A位置(同一位置放入同一位置)。
循环结束,分成两堆[0,0]和[1,1],并继续进行递归调用,满足递归出口条件l >= r直接结束。
第二段:
[2,1],这段满足递归出口条件l >= r,直接结束。

源代码

def quick_sort(L,start,end):
    a=start
    b=end
    mid=L[a]
    if a>=b:
        return 
    while a<b:
        while a<b and L[b]>mid:
            b-=1
        L[a]=L[b]
        while a <b and L[a]<mid:
            a+=1
        L[b]=L[a]
    L[a]=mid
    quick_sort(L,start,a)
    quick_sort(L,a+1,end)
    return l
l = [5,3,1,6,9,2,11]
quick_sort(l,0,len(l)-1)

算法分析

最佳情况:T(n) = O(nlogn) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(nlogn)
空间复杂度O(nlogn),属于内部排序,不稳定

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值