所谓快速排序,咱们就是说突出一个字:快!他是所有排序算法中最快的算法。
接下来我给大家讲一下快速排序的思路:
- 取一个元素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将列表分为两部分时他们的相对位置会改变,稳定性自然变差了。
这就是我所理解的快速排序算法
🌸🌸🌸🌸🌸🌸完结撒花!🌸🌸🌸🌸🌸🌸
如有疑问或错误,欢迎大家评论区留言指出,谢谢支持!!