核心思想
快速排序的核心思想在于在数组中寻找元素作为pivot(pivot可以简单理解为“基准值”的意思),然后将小于pivot的元素放在pivot的左边,大于pivot的值放在pivot的右边,这步操作叫做partition(partition是“分区”的意思),然后在pivot的左边和右边执行同样的partition操作,快速排序的基本流程如下:
1.选定一个值作为pivot
2.对整个数组执行partition操作
3.在pivot的左边和右边执行partition操作
代码实现
快速排序的原理理解起来不难,关键在于partition操作的实现,partition的实现有三种之多,在这里我介绍较容易理解的(其它的我也不会啦,暂时没学),代码如下:
def partition(arr, left, right):
pivot = arr[(left + right) // 2]
arr[(left + right) // 2], arr[right] = arr[right], arr[(left + right) // 2] # 直接选用right所指的值则该算法不会存在best case
i = left
for j in range(left, right):
if arr[j] <= pivot:
arr[j], arr[i] = arr[i], arr[j]
i += 1
arr[i], arr[right] = arr[right], arr[i]
return i
首先选取pivot,这里我选取的是数组的中间值作为pivot,pivot的选取不建议选取数组最左端或最右端的值,因为这样的话该算法不会出现最好情况(即best case),然后将pivot和数组最右端的元素交换,目的是方便后面的交换。然后是关键的partition操作,为了实现partition操作,我们定义两个指针i和j,使用j遍历这个数组,将j所指的小于等于pivot的元素与i所指元素交换,i指针右移,这样的操作能够保证i左侧的1元素都小于等于pivot,i右侧的元素(除pivot自身外)都大于pivot,实质上该操作将数组分为了三部分:
1.pivot自身
2.小于等于pivot的区间
3.大于pivot的区间
当j遍历到n-1(其中n是数组长度)时结束遍历,最后将i所指的元素与pivot(即right所指的元素)进行交换,即完成了partiton操作的实现,完整代码如下:
def partition(arr, left, right):
pivot = arr[(left + right) // 2]
arr[(left + right) // 2], arr[right] = arr[right], arr[(left + right) // 2] # 直接选用right所指的值则该算法不会存在best case
i = left
for j in range(left, right):
if arr[j] <= pivot:
arr[j], arr[i] = arr[i], arr[j]
i += 1
arr[i], arr[right] = arr[right], arr[i]
return i
def quick_sort(arr, left, right):
if left >= right:
return
res = partition(arr, left, right)
quick_sort(arr, left, res - 1)
quick_sort(arr, res + 1, right)
return arr
quick_sort自身是个递归函数,它的结束条件是,当left>=right时,即区间内最多只有一个元素时,直接结束,因为一个元素的区间永远是有序的。然后调用partition操作,需要注意的是,partion操作需要返回pivot的索引(即i的值),以便于后续递归操作区间的确定。后递归调用quick_sort自身,最后返回数组即可。
复杂度分析
时间复杂度
最好情况
quick_sort算法的最好情况为:每次所选取的pivot都正好是数组或区间的中位数,这时partition操作正好能够将数组一分为二,partition操作的深度为,而partition本身的操作的时间复杂度为,故最好情况的时间复杂度为
最坏情况
quick_sort算法的最坏情况为:每次选取的pivot都将数组或区间分为0个元素和n-1个元素(其中n是数组或区间的长度),即给定数组是有序的,这时partition操作要执行n次,而partition操作自身的时间复杂度为,故最坏情况的时间复杂度为,但由于我们选取的pivot是数组或区间的中间数,故我们的算法不会存在最坏情况
平均情况
quick_sort算法平均情况下的时间复杂度即最好情况下的时间复杂度和最坏情况下的时间复杂度的平均,即
空间复杂度
由于quick_sort算法运行过程中没有创建新的数组,只有几个变量的存在,故quick_sort的空间复杂度为