NB三人组之一 —— 快速排序

所谓快速排序,咱们就是说突出一个字:快!他是所有排序算法中最快的算法。

接下来我给大家讲一下快速排序的思路:

  •   取一个元素p(第一个元素)进行归位,什么叫归位呢?就是放到他应该在的地方,使列表分为两部分左边全比他小(大),右边全比他大(小)。
  • 递归完成排序

其中最重要的一步就是归位,快速排序围绕着他来写。我用一张图来说明归位的作用。

这样一来元素P归为完成。使左边的数都比他小,右边的数都比他大啦。

下面我们用代码来实现它

​
def partition(lst,left,right):
    temp=lst[left]
    while left<right:
        '从右边开始找比temp小的数 填充左边位置'
        while lst[right]>=temp and left<right:  # left<right 防止出格
            right-=1 # 往左走一位
        lst[left]=lst[right]    # 把右边的值放到左边空位上
        while left<right and lst[left]<=temp:   # 从左边找比temp大的数放到right的空位上
            left+=1
        lst[right]=lst[left]    # 把左边的值写到右边的位置上
        print(lst)
    lst[left]=temp  # 把temp归位
    return lst

lst=[5,7,4,6,3,1,2,9,8]
print(partition(lst,0,8))

​

注意里层循环判断时也要加上left<right哦,不然有可能会超出索引哦

我们来运行一下 结果为:

[2, 1, 4, 3, 5, 6, 7, 9, 8]

当我们每次循环完时打印列表就可以看到具体过程,过程如下:

原列表为:

[5, 7, 4, 6, 3, 1, 2, 9, 8]


[2, 7, 4, 6, 3, 1, 7, 9, 8]   

这一步将5作为temp储存了起来,从右边开始遍历列表寻找比temp小的数放到左边left的位置,当遍历到2时满足条件,将它赋值给lst[left](并不是交换),列表开始从左边循环目的为填充右边的值,当遍历到7时满足条件,将它赋值给lst[right],至此,一次循环结束。


[2, 1, 4, 6, 3, 6, 7, 9, 8]

这时right从7开始往前遍历[2, 7, 4, 6, 3, 1, 7, 9, 8] 这个列表遍历到1时赋值给lst[left],接着同理开始从left开始向右遍历.....


[2, 1, 4, 3, 3, 6, 7, 9, 8]

同理,自行推理


[2, 1, 4, 3, 5, 6, 7, 9, 8] 当left=right时说明列表两端遍历都完成了右边全是比temp大的数左边全是比temp小的数,所以将temp赋值给lst[right],即temp要归位的地方


理解完partition函数接下来的快速排序就是在partition函数的基础上不断递归来完成的

具体的代码如下

def partition(lst,left,right):
    temp=lst[left]
    while left<right:
        '从右边开始找比temp小的数 填充左边位置'
        while lst[right]>=temp and left<right:  # left<right 防止出格
            right-=1 # 往左走一位
        lst[left]=lst[right]    # 把右边的值放到左边空位上
        while left<right and lst[left]<=temp:   # 从左边找比temp大的数放到right的空位上
            left+=1
        lst[right]=lst[left]    # 把左边的值写到右边的位置上
    lst[left]=temp  # 把temp归位
    return left


def quick_sort(lst,left,right):
    if left<right:  # 至少为两个元素
        mid=partition(lst,left,right)
        quick_sort(lst, left, mid - 1)
        quick_sort(lst, mid + 1, right)


lst=list(range(1,100))
import random
random.shuffle(lst)
print(lst)
quick_sort(lst,0,len(lst)-1)
print(lst)
​

quick_sort函数在partition基础逐步递归来排序,将partition函数的返回值设为left或right,令mid等于partition函数的返回值以至于让原来的列表分为两部分来再次partition,注意递归的终止条件为left<right,说明至少需要partition的至少有两个元素。递归完成后列表排序完成。

结果为:

 接下来我们来讨论此算法的时间复杂度(●'◡'●)

快速排序的时间复杂度由两部分组成一部分是partition函数,一部分是quick_sort函数

我举一个特殊的例子,用图来表示

quick_sort遍历了logn次因为每一层都减一半,时间复杂度为O(logn),partition函数从left<right遍历到left=right相当于便利了整个列表,时间复杂度为O(n),所以整个函数的时间复杂度为O(nlogn)

但是快速排序的时间复杂度有最坏情况,如果列表中的元素是倒序排好的情况,每次partition函数只能归位一个元素导致所以整个函数的时间复杂度变为O(n^2),但是最坏情况很少发生


 快速排序虽然块但是它还是有弊端的哦

1.Python的递归存在最大深度,最大深度为999

可能会出现这样的问题

RecursionError: maximum recursion depth exceeded in comparison

但是我们是可以人为修改的只需要导入sys模块修改即可

import sys

sys.setrecursionlimit(5000) # 设置最大递归深度为5000

2.凡是涉及到递归都要涉及内存空间问题

程序使用递归实现时,系统会分配大量的内存
这是因为,每一次递归的实现中,系统都会重新为变量分配空间而不是覆盖原来的空间。

所以快速排序用空间换了时间。 

3.快速排序稳定性问题

要了解稳定性问题就需要先了解稳定性,什么是稳定性呢?举个例子[2(一号位),3,2(二号位),1,!]这个列表当二号位的2与一号位的2位置互换了,他们的相对位置改变了,稳定性就变差了

相比于冒泡排序这种相邻两部分比较的排序来说,快速排序显得不是那么稳定当partition将列表分为两部分时他们的相对位置会改变,稳定性自然变差了。

这就是我所理解的快速排序算法

🌸🌸🌸🌸🌸🌸完结撒花!🌸🌸🌸🌸🌸🌸

如有疑问或错误,欢迎大家评论区留言指出,谢谢支持!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值