快速排序
快速排序核心:二叉树的前序遍历+对撞型双指针
快速排序的基本过程
快速排序是将分治法运用到排序问题的典型例子
基本思想:
通过一个标记pivot元素将n个元素的序列划分为左右两个子序列left和right;
left序列中元素都比pivot小(如果存在重复元素,left序列中元素小于或等于pivot);
right序列中元素都比pivot大(如果存在重复元素,right序列中元素大于或等于pivot);
然后left序列和right序列各自再执行快速排序,left和right序列排好序之后,整个序列就有序了
这里排序进行左右划分的时候是一直划分到子序列只包含一个元素的时候,然后在递归返回
代码实现
def quick_sort(array, start, end):
if start >= end:
return
// 这里就是一个对撞的双指针操作
pivot = array[(start + end) // 2]
left, right = start, end
while left <= right:
while left <= right and array[left] < pivot:
left += 1
while left <= right and array[right] > pivot:
right -= 1
if left <= right:
array[left], array[right] = array[right], array[left]
left += 1
right -= 1
// 先处理元素再分别递归处理两侧分支,与二叉树的前序遍历非常像
quick_sort(array, start, right)
quick_sort(array, left, end)
if __name__ == '__main__':
array1 = []
array2 = [1]
array3 = [0, 1]
array4 = [26, 53, 48, 15, 13, 46, 32, 14]
array5 = [26, 53, 48, 15, 13, 46, 32, 15]
array6 = [26, 2, 10, 6, 26, 45, 77, 30, 26]
quick_sort(array1, start=0, end=len(array1) - 1)
print(array1)
quick_sort(array2, start=0, end=len(array2) - 1)
print(array2)
quick_sort(array3, start=0, end=len(array3) - 1)
print(array3)
quick_sort(array4, start=0, end=len(array4) - 1)
print(array4)
quick_sort(array5, start=0, end=len(array5) - 1)
print(array5)
quick_sort(array6, start=0, end=len(array6) - 1)
print(array6)
判定条件也可简化,如下面代码
def quick_sort(array, start, end):
if start >= end:
return
// 这里就是一个对撞的双指针操作
pivot = array[(start + end) // 2]
left, right = start, end
while left < right:
while array[left] < pivot:
left += 1
while array[right] > pivot:
right -= 1
if left <= right:
array[left], array[right] = array[right], array[left]
left += 1
right -= 1
// 先处理元素再分别递归处理两侧分支,与二叉树的前序遍历非常像
quick_sort(array, start, right)
quick_sort(array, left, end)
if __name__ == '__main__':
array1 = []
array2 = [1]
array3 = [0, 1]
array4 = [26, 53, 48, 15, 13, 46, 32, 14]
array5 = [26, 53, 48, 15, 13, 46, 32, 15]
array6 = [26, 2, 10, 6, 26, 45, 77, 30, 26]
quick_sort(array1, start=0, end=len(array1) - 1)
print(array1)
quick_sort(array2, start=0, end=len(array2) - 1)
print(array2)
quick_sort(array3, start=0, end=len(array3) - 1)
print(array3)
quick_sort(array4, start=0, end=len(array4) - 1)
print(array4)
quick_sort(array5, start=0, end=len(array5) - 1)
print(array5)
quick_sort(array6, start=0, end=len(array6) - 1)
print(array6)
快速排序的第二种实现
思路分析
代码实现
def quick_sort(arr, left, right):
if left >= right:
return
pivot = arr[right]
i = left - 1
for j in range(left, right):
if arr[j] <= pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i]
arr[i + 1], arr[right] = arr[right], arr[i + 1]
quick_sort(arr, left, i)
quick_sort(arr, i + 1, right)
if __name__ == '__main__':
array1 = []
array2 = [1]
array3 = [0, 1]
array4 = [26, 53, 48, 15, 13, 46, 32, 14]
array5 = [26, 53, 48, 15, 13, 46, 32, 15]
array6 = [26, 2, 10, 6, 26, 45, 77, 30, 26]
quick_sort(array1, left=0, right=len(array1) - 1)
print(array1)
quick_sort(array2, left=0, right=len(array2) - 1)
print(array2)
quick_sort(array3, left=0, right=len(array3) - 1)
print(array3)
quick_sort(array4, left=0, right=len(array4) - 1)
print(array4)
quick_sort(array5, left=0, right=len(array5) - 1)
print(array5)
quick_sort(array6, left=0, right=len(array6) - 1)
print(array6)
时间复杂度分析
如果我们选择的pivot每次都是正好在中间,效率是最高的;但这无法保证,我们需要从最好、最坏和中间的情况来分析
-
最坏的情况:每次选择的恰好是low节点作为pivot,如果元素恰好都是逆序的,此时时间复杂度为 O(n^2)
-
最好的情况:如果元素恰好都是有序的,此时时间复杂度为 O(n)
-
折中的情况:每次选择的都是中间节点,此时序列每次都是长度相等的序列,此时时间复杂度为 O(nlogn)