思想
快速排序(快排)是非常常用的排序方法,在技术面试中出现频率也特别高。它主要采用交换和分治的策略进行排序。是不稳定排序。
步骤:
1、在序列中选一个元素作为划分的基准元素(pivot)
2、将所有不大于pivot的数字放在pivot的前面,大于pivot的数字放在pivot的后面
3、以pivot为界,对前后两个子序列分别递归重复前两步,直至区间内只有一个元素
示例
对序列 [2, 4, 7, 3, 6, 5] 按升序排列,取倒数第一个元素为pivot,tail表示不大于pivot的序列的最后一个数的下标,所以最后基准元素的下标为tail + 1
pivot | tail | 排序过程 |
---|---|---|
5 | -1 | [2, 4, 7, 3, 6, 5] |
5 | 0 | [2, 4, 7, 3, 6, 5] |
5 | 1 | [2, 4, 7, 3, 6, 5] |
5 | 1 | [2, 4, 7, 3, 6, 5] |
5 | 2 | [2, 4, 7, 3, 6, 5] -> [2, 4, 3, 7, 6, 5] |
5 | 2 | [2, 4, 3, 7, 6, 5] |
5 | 2 | [2, 4, 3, 5, 6, 7] (交换下标为tail+1的元素和pivot) |
至此,前后两个子序列划分完毕,下面继续对子序列进行排序
pivot | tail | 排序过程 |
---|---|---|
3 | -1 | [2, 4, 3] |
3 | 0 | [2, 4, 3] |
3 | 0 | [2, 4, 3] |
3 | 0 | [2, 3, 4] (交换下标为tail+1的元素和pivot) |
pivot | tail | 排序过程 |
---|---|---|
7 | -1 | [6, 7] |
7 | 0 | [6, 7] |
7 | 0 | [6, 7] (交换下标为tail+1的元素和pivot) |
代码
class Solution:
# @param {int[]} A an integer array
# @return nothing
def sortIntegers2(self, A):
# Write your code here
if A is None or len(A) <= 1:
return
s = 0
e = len(A) - 1
self.quickSort(A, s, e)
def quickSort(self, A, s, e):
if s < e:
# 基准元素下标
pivot_ind = self.partition(A, s, e)
self.quickSort(A, s, pivot_ind - 1)
self.quickSort(A, pivot_ind + 1, e)
def partition(self, A, s, e):
# 选取倒数第一个元素为基准元素
pivot = A[e]
# tail表示不大于pivot的序列的最后一个数的下标,所以最后基准元素的下标为tail + 1
tail = s - 1
for i in range(s, e):
if A[i] <= pivot:
tail += 1
self.swap(A, i, tail)
self.swap(A, tail + 1, e)
return tail + 1
def swap(self, A, i, j):
if i != j:
tmp = A[i]
A[i] = A[j]
A[j]= tmp
选取第一个元素为基准元素
def partition(self, A, s, e):
# 选取第一个元素为基准元素
pivot = A[s]
# tail表示不小于pivot的序列的第一个数的下标,所以最后基准元素的下标为tail - 1
tail = e+1
for i in range(e, s,-1):
if A[i] >= pivot:
tail -= 1
self.swap(A, i, tail)
self.swap(A, tail - 1 , s)
return tail - 1
时间复杂度
快排的时间复杂度比较稳定,为 O(nlogn)