列表排序的重要排序有三种,分别是 快速排序、堆排序和归并排序。
这里我们来讨论 快速排序:
快速排序
快速排序的特点就是突出“快”,它的排序思路如下:
①取一个元素p(可以是任意一个元素),使元素p“归位”
②“归位”即列表被p分为两部分,左边都比p小,右边都比p大
③不断递归以上过程,直到完成排序
上图就是一趟快速排序(这里默认列表第一个元素为p),在p归位后,可见列表分为了两部分,则下一步需要在两部分中同时再递归调用以上过程,以此类推直到完成排序,结果如下:
所以不难发现快速排序分为两部分,内是让元素p归位的“归位函数”,外是递归调用归位函数的“排序函数”
快速排序代码
归位函数的代码如下:
def partition(list,left,right):
tmp=list[left] #默认第一个元素为元素p
while left<right: #大前提条件,防止越界
while left<right and list[right]>=tmp: #从最右边开始,直到找到小于p的元素
right-=1 #没找到,向左走一步
list[left]=list[right] #找到小于p时,放到左边空位去
while left<right and list[left]<=tmp: #从左边开始找,直到找到大于p的元素
left+=1 #没找到,向右走一步
list[right]=list[left] #找到大于p时,放到右边空位去
list[left]=tmp #最后left=right时,将p元素放到这个位置,即完成了该次归位
return left
注意:每趟的归位过程都是一右一左进行的(即右边找到目标元素后再从左边找,不断循环到归位为止)
排序函数的代码如下:
def quick_sort(list,left,right):
'''
:param list:列表
:param left:排序区域的第一个元素的下标
:param right:排序区域的最后一个元素的下标
'''
if left<right: #表示列表至少两个元素
mid=partition(list,left,right) #调用“归位函数”
quick_sort(list,left,mid-1) #p归位后的左部分继续递归
quick_sort(list,mid+1,right) #p归位后的右部分继续递归
list=[5,7,9,6,5,4,5,3,8]
quick_sort(list,0,len(list)-1)
print(list)
运行结果如下:
[3, 4, 5, 5, 5, 6, 7, 8, 9]
快速排序时间复杂度
将快速排序的过程理解之后,我们来思考一下这种排序算法的时间复杂度是多少呢?
内层函数每一趟都会遍历一遍所排序的列表,时间复杂度为n;外层函数每一次归位会将所走区域折半,时间复杂度为logn,所以快速排序的时间复杂度应该是O(nlogn)。
快速排序的问题
快速排序有一种极端情况,也就是把每次归位所分的两边区域总有一边元素个数为0或1的情况称作“最坏情况”,当“最坏情况”出现时,快速排序的时间复杂度就变成了O(n²)
提示:下一篇为重要排序篇——堆排序