快速排序Quick Sort
Quick Sort
主要思想:
1、递归;
2、让元素去到自己该去的地方(左边都比它小,右边都比它大)
约定:首先归位第一个元素
将第一个元素提出并存储为temp;
设置left指向列表最左边,right指向列表最右侧,从列表右侧开始向左遍历,把每一个元素都与temp比较:如果比temp大,那么right向左移动一位,继续比;如果比temp小,就把这个值赋值给left此时所指的位置;然后从left+1的位置开始遍历,如果遇到比temp小的,left向右移动一位,继续比较;如果比temp大的,就把这个值赋值给right此时所指的位置,以此往复,直到left与right重合时,此时的位置,就是temp该在的位置
演示如下:
# 原列表 [5, 6, 3, 7, 4, 1, 8, 2, 9],5存起来
# 第一次,从9开始,9比5大,看前一位的2,2比5小,就把2放在原来5的位置
right [2, 6, 3, 7, 4, 1, 8, 2, 9]
# 第二次,从6开始,6比5大,就把6放在原来2的位置
left [2, 6, 3, 7, 4, 1, 8, 6, 9]
# 第三次,从8开始,8比5大,看前一位的1,1比5小,就把1放在原来6的位置
right [2, 1, 3, 7, 4, 1, 8, 6, 9]
# 第四次,从3开始,3比5小,看后一位的7,7比5大,就把7放在原来1的位置
left [2, 1, 3, 7, 4, 7, 8, 6, 9]
# 第五次,从4开始,4比5小,就把4放在原来7的位置
right [2, 1, 3, 4, 4, 7, 8, 6, 9]
# 第六次,从4开始,此时left与right重合,指向原列表的4的位置
left [2, 1, 3, 4, 4, 7, 8, 6, 9]
# 最后,把存起来的5放在这个位置
end [2, 1, 3, 4, 5, 7, 8, 6, 9]
运用递归的方法,将 归位好的数的两边切片为两个小列表,继续归位,直到左右指针(left、right)重合。代码如下:
# 归位函数
def partition(list,left,right):
temp = list[left] # 存储最左值
while left < right: # 用循环保证temp能够去到该去的位置,left<right是控制循环结束的条件
# 先从右边找比temp小的数
while left < right and list[right] >= temp:
right -= 1
list[left] = list[right]
# 再从左边找比temp大的数
while left < right and list[left] <= temp:
left += 1
list[right] = list[left]
list[left] = temp
return left
# 快速排序函数
def quick_sort(list,left,right):
if left < right:
mid = partition(list,left,right)
quick_sort(list,left,mid-1)
quick_sort(list,mid+1,right)
return list
-----------------------------------------------
list3 = [5,6,3,7,4,1,8,2,9]
print(quick_sort(list3,0,len(list3)-1))
---->[1, 2, 3, 4, 5, 6, 7, 8, 9]
-
外层循环的left<right是为了控制循环结束,循环的作用又是为了使内层的两个小循环往复作用,而不是各走一次就停下
-
内层循环的left<right也是为了控制循环结束,因为整体上是left与right向内移动,找到两者重合的位置,所以要设置left<right,内层循环跳出,在外层循环也跳出,就是时候把目标数放到这个地方去
-
partition函数中内层的两个小循环的条件中>=和<=,当遇到与temp值相等的数,放左边与放右边其实没什么区别,都行,但还是要移动的
-
partition函数返回的是temp值的下标,因为两个指针都重合了,就取left了
-
在quick_sort函数中,递归调用时的切片,一个是从left开始到mid-1,另一个是从mid+1到right
-
时间复杂度为O(nlogn),用不那么严谨的方法推导:假定每次切片都是刚好对半开,那么就是每次递归都在二分列表,所以就是O(logn);partition函数虽然有两层循环,但实际上整个列表只遍历了一次,所以时间复杂度是O(n),所以整个快速排序算法就是O(nlogn)
-
递归对于python有递归最大深度,会消耗一定的系统资源
-
快速排序的最坏情况:
# 当列表为[9,8,7,6,5,4,3,2,1]时,9被提出 # 第一次,从右边找,1比9小,1放在原来9的位置,9放在1的位置上9只有左边有数,右边是空的 [1, 8, 7, 6, 5, 4, 3, 2, 9] # 第二次,在列表[1, 8, 7, 6, 5, 4, 3, 2]中重新调用partition函数继续 # 发现1就在原本的位置上,又对右侧的列表[8, 7, 6, 5, 4, 3, 2]继续调用partition函数 # 以此类推,每一次递归调用都只能归位一个元素这种情况下,快速排序的时间复杂度就达到了O(n的平方)
-
对于时间复杂度,有:最快时间复杂度,一般时间复杂度和最坏时间复杂度,通常情况下只考虑后两种

浙公网安备 33010602011771号