190417
快速排序
快速排序一般来说会比选择排序更快,是使用递归的思路来解决排序问题的。
首先,来了解下递归。使用递归必须满足以下两点:
- 基线条件
- 递归条件
基线条件是使递归停止调用的条件,如果一个函数被不停的调用,占满全部内存,就会“死”。而递归条件,就是函数调用的条件。递归必须缩小问题的规模,且基线条件要简单。每次递归调用后必须离基线条件更近一步。对于参数是数组的情况来说,停止条件一般是空数组或者数组长度为1。总体来说,递归的思路就是“ 分而治之Devide&Conquer”。适用于一小块地的最大方块,同样是适用这一整块地的最大方块。分解问题,是递归的开始。(解决递归占用内存过大的问题:改成循环or使用尾递归)
接下来,看一下快速排序的流程:
- 先从数组中选出一个元素做基准值(pivot)
- 将数组中的值按照比基准值大,比基准值小的规则分成两个子数组([小于pivot的子数组]+[pivot]+[大于pivot的子数组]
- 对两个子数组继续进行选基准值、分大小操作,直至最终的子数组中只含一个元素
- 数组排序完成
如下示意:待排序数组[5, 3, 1, 2, 4]
选择5做pivot,则有
原数组被分为[], [3, 1, 2, 4],接着选3作为pivot
子数组被分为[1, 2], [4],接着选1作为pivot
子数组被分为[], [2]。最后按照左+pivot+右的顺序将数组还原回去,排序完成。
Python3.6实现
def QuickSort(array):
if len(array) < 2:
return array
else:
pivot = array[0]
smaller_than_pivot = [item for item in array[1:] if item <= pivot]
bigger_than_pivot = [item for item in array[1:] if item > pivot]
return QuickSort(smaller_than_pivot) + [pivot] + QuickSort(bigger_than_pivot)
if __name__ == '__main__':
test_sample = [1, 16, 9, 8, 10, 11, 28, 99, 33, 21]
print(QuickSort(test_sample))
运行结果:
最后,讨论下快速排序的算法复杂度,最佳情况是O(nlogn),最糟情况是O(n2).取决于pivot的选取。对于给定排序的数组是有序的情况来说,pivot选择第一个元素,就要调用N次,每次检查N个元素,总的复杂度就是O(n2)。但是如果pivot选择中间的元素,调用的层数就是logN,每次检查的元素还是N个,总的复杂度就是O(n*logn)。