介绍
快速排序(QuickSort)是一种高效的排序算法,最早由Tony Hoare于1959年提出。它采用分治策略来排序,具有时间复杂度为O(nlogn)的优异性能,因此在实际应用中广泛使用。
算法思路
快速排序运用了分治(Divide and Conquer)的思想,分为分解、解决子问题和合并三个步骤。
1.分解
选择一个基准元素(pivot),将要排序的数组(subarray)按照基准元素进行划分,使得所有小于基准元素的元素在其左边,所有大于基准元素的元素在右边。
2.解决子问题
递归地对左右两部分子数组进行快速排序,直到子数组的长度为1或0。
3.合并
因为左右两部分子数组都已排好序,将左右两部分子数组及基准元素排列合并,得到最终有序数组。
综上,快速排序的分治方法是,选定一个基准元素,将序列分为小于和大于基准元素的两个子序列,再分别对子序列进行排序,最后再拼接两个序列即可。
def quick_sort(arr,low,high):
"""
arr:待排序数组
low:序列最小下标
high:序簇最大下标
"""
if low >= high:
return
p = partition(arr, low, high) # 找到主元素
quick_sort(arr, low, p - 1) # 对左右子序列快速排序
quick_sort(arr, p + 1, high)
def partition(arr,low,high):
pivot = arr[low] # 初始主元素,可以随意选择
while low < high:
while low < high and arr[high] >= pivot: # 向前寻找第一个小于主元素的值
high -= 1
arr[low] = arr[high]
while low < high and arr[low] <= pivot: # 向后寻找第一个大于主元素的值
low += 1
arr[high] = arr[low]
arr[low] = pivot # 将主元素放入其最终位置,通过它将数组分为两部分
return low
下面,我们来对上面所述的算法进行简单说明:
首先,将数组中的第一个元素作为基准元素(pivot)。
接着,从后向前寻找一个小于基准元素的值arr[high],并将其赋值给arr[low],之后从前向后寻找一个大于基准元素的值arr[low],并将其赋值给arr[high]。
若arr[low] > pivot,则第一次循环结束,在low、high位置上有相等的值,此时需要将基准元素放入位置low处,将数组分为左右两部分,并返回这个位置low。
若arr[low] < pivot,则low位置上的值经过上一步操作已经与high位置上相等的值进行了交换,此时将high位置上的值放入low位置即可。高位指针变成了数组中恰好小于基准元素的值的位置,从而可以直接进行下一次循环。
需要注意的是,快速排序不是稳定排序,所以有可能使得本来相等的多个元素之间的先后顺序发生改变。
优化思路
1. 三数取中法
在对数组划分时,若总是选择数组中的第一个或最后一个元素作为基准元素,有可能导致最坏情况的出现(即每次划分只能将数组缩短1)。三数取中法是一种优化方法,即在选择pivot之前,随机选择3个数,取其中位数作为pivot,以保证每一次划分都使得数组缩短至少1/4。
def partition(arr,low,high):
mid = (low + high) // 2 # 选取中间值
if arr[mid] < arr[low]:
arr[mid],arr[low] = arr[low],arr[mid] # 保证第一个元素最小
if arr[mid] > arr[high]:
arr[mid],arr[high] = arr[high],arr[mid] # 保证最后一个元素最大
pivot = arr[low]
while low < high:
while low < high and arr[high] >= pivot: # 向前寻找第一个小于主元素的值
high -= 1
arr[low] = arr[high]
while low < high and arr[low] <= pivot: # 向后寻找第一个大于主元素的值
low += 1
arr[high] = arr[low]
arr[low] = pivot # 将主元素放入其最终位置,通过它将数组分为两部分
return low
2. 插入排序
在划分出的子序列长度小于一定值(如10)的时候,可以视为已经有序,不需要再做快速排序,可以切换为插入排序算法,即把子序列插入到有序序列中。
def quick_sort(arr,low,high):
"""
arr:待排序数组
low:序列最小下标
high:序簇最大下标
"""
if high - low <= 10: # 当序列长度小于等于 10 时直接插入排序
insert_sort(arr, low, high)
return
if low >= high:
return
p = partition(arr, low, high) # 找到主元素
quick_sort(arr, low, p - 1) # 对左右子序列快速排序
quick_sort(arr, p + 1, high)
def insert_sort(arr, low, high):
for i in range(low + 1, high + 1):
key = arr[i]
j = i - 1
while j >= low and arr[j] > key:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
总结
快速排序是一种非常高效的排序算法,快速排序通过对问题的划分和逐步缩小,快速得到问题的解。这就是快速排序算法中的分治思想。在这篇文章中,我们介绍了快速排序算法的核心思想、python代码实现和优化,包括三数取中法和插入排序优化。在对于小规模的数组排序时,我们可以采用插入排序以获得更好的性能。快速排序虽然不同于人们常见的排序方法,但其流程简明,代码优雅,没有繁琐的数据结构,依赖性也很小,是一种优秀的排序方法。