快速排序(Quick Sort)是一种高效的排序算法,其基本思想是采用分治法(Divide and Conquer)。通过一次排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

原理

  1. 选择基准值:从数列中挑出一个元素,称为“基准”(pivot)。

  2. 分割操作:重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区操作(partition)。

  3. 递归排序子序列:递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

实现

以下是快速排序的Python实现:

1
2
3
4
5
6
7
8
9
10
11
12
def quicksort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quicksort(left) + middle + quicksort(right)

# 测试代码
arr = [3,6,8,10,1,2,1]
print(quicksort(arr))

这个实现非常直观,但是使用了额外的空间来创建三个列表(left, middle, right)。在实际应用中,通常会使用原地快速排序(in-place quicksort),这样可以节省空间。

下面是原地快速排序的Python实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def partition(arr, low, high):
i = low - 1 # 指向最小元素的指针
pivot = arr[high] # 选择最右边的元素作为基准值

for j in range(low, high):
# 如果当前元素小于或等于基准值
if arr[j] <= pivot:
i = i + 1 # 增加最小元素指针
arr[i], arr[j] = arr[j], arr[i] # 交换

arr[i + 1], arr[high] = arr[high], arr[i + 1] # 将基准值放到最终位置
return i + 1

def quickSort(arr, low, high):
if len(arr) == 1:
return arr
if low < high:
pi = partition(arr, low, high) # pi是分区索引,arr[p]现在位于正确的位置
quickSort(arr, low, pi - 1) # 对左边子数组递归排序
quickSort(arr, pi + 1, high) # 对右边子数组递归排序

# 测试代码
arr = [10, 7, 8, 9, 1, 5]
n = len(arr)
quickSort(arr, 0, n - 1)
print("排序后的数组:")
for i in range(n):
print("%d" % arr[i]),

在这个实现中,partition函数负责选取基准值并重新排列数组,使得基准值左侧的元素都小于它,右侧的元素都大于它。然后,quickSort函数递归地对左右两部分子数组进行排序。

注意

  1. 快速排序的平均时间复杂度是O(n log n),但在最坏情况下(输入数组已经有序或逆序)会退化到O(n^2)。通过随机化选择基准或使用“三数取中”法可以避免最坏情况的发生。

  2. 快速排序是不稳定的排序算法,即如果序列中存在两个相等的元素,快速排序可能会改变它们的相对位置。

  3. 快速排序是一种原地排序算法,不需要额外的存储空间,除了递归调用栈所使用的空间外。