快速排序及其Python实现【图解算法】

快速排序及其Python实现【图解算法】

1. 引出问题

假设你的手机中存储了很多乐曲,对于每个乐队,你都记录了其作品被播放的次数。

乐队播放次数
RADIOHEAD156
KISHOKE KUMAR141
THE BLACK KEYS35
NEUTRAL MILK HOTEL94
BECK88
THE STROKES61
WILCO11

你想将乐队按照播放次数从多到少进行排列,从而将你喜欢的乐队排序,怎么做呢?

2. 选择排序

我们最初的思路可能类似于选择排序,即每次都选择播放量最高的乐队转移进一个新列表,直到旧列表中没有任何数据。

新列表就是排序完成的结果,算法链接为:选择排序

3. 快速排序

快速排序的核心思想是分而治之(D&C:divide and conquer),是递归式解决方案。

D&C解决问题包括两个步骤:

(1)找出基线条件,这种条件必须尽可能简单
(2)不断将问题分解(或者说缩小规模),直至其符合基线条件。

基线条件就是停止递归(或者说循环)的条件,这里排序最简单的条件是什么呢?大家看这样的数组:

数组解释
[]空数组
[20]只包含一个元素的数组

这两种情况,我们需要对数组进行排序吗?当然不!

思路来了,我们要把数组分解成类似上面的两种情况,首先看到我们的数组:
在这里插入图片描述
进行第一步分解,选择中间位置 location=ceil(len(arr)/2)=4,这个值是94。

(注意1:因数组本身是无序的,所以选择的元素位置并没有规定,随便选,这里只是为了便于理解)

这里的94即是我们第一步分解的基准值,我们将其他元素与之比较大小,建立两个新的子数组arr1和arr2:

在这里插入图片描述
可以看到,这两个子数组并没有排序,只是按照大于或小于35进行了分类,我们继续分解(以arr2为示例):

arr2,选择中间位置 location=ceil(len(arr2)/2)=1,因此基准值是156,再次进行分类:
在这里插入图片描述
这里我们把arr2分为了arr3和arr4,这两个结果就符合我们的基线条件,不需要任何排序操作,返回原来的值即可。

同样的把arr1分解之后,如果不符合基线条件,则继续分解,直至符合基线条件。

这就是整个快速排序的算法流程,核心就是分而治之和基线条件。

我们执行了多少次元素检查呢?

最差情况下,我们每次选择的基准值都使一个子数组为空,需要执行n+(n-1)+…+1次检查,和选择排序一致,为O(n²)。

最好情况下,我们选择的基准值都使子数组元素数量一致,执行n+n-1+…,共ceil(log(n))层检查,时间为O(n×log n)。

4. Python代码(升序排列)

键入以下代码并运行:

uickSort函数作用:对数组进行快速排序(降序)
## 输入:
##      array:传入的数组
## 输出:
##      return :完成排序的数组
def quickSort(array):
    if len(array)<2: # 基线条件判断,如果符合,直接返回
        return array
    else:
        pivot=array[0] # 选择基准值,这里选的第一个值,随便选都行

        greater=[i for i in array[1:] if i>pivot] # 找到大于基准值的数,放入子数组1

        less=[i for i in array[1:] if i<=pivot] # 找到小于基准值的数,放入子数组2

        return quickSort(greater)+[pivot]+quickSort(less) # 进行迭代递归,直至所有子数组达到基线条件

    ## 测试代码

print(quickSort([156,141,94,88,61,35,11]))

这里对代码进行了详尽的注释,因此不再赘述,结果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值