快速排序利用分治思想:
- 确定分界点
x
;- 可取左边界
l
、右边界r
、中间点,也可以随机取。 x
点指向的数叫作 pivot。
- 可取左边界
- 用
x
将原先区间划分为两个区间,左区间的值都<= x
,右区间的值都>= x
;- 指针
pl
先开始从左往右移动; pl
移动到>= x
的数停住;- 必须要有
=
- 必须要有
- 指针
pr
开始从右往左移动; pr
移动到<= x
的数停住;- 必须要有
=
- 必须要有
- 交换
pl
和pr
指向的两个数; pl
和pr
继续按照这一规则移动;- 终止条件是
pl >= pr
(双指针交汇),这时pl
左边的数都<= x
,pr
右边的数都>= x
。- 每一步操作后都满足
pr
右边的数>= x
,双指针交汇后pl
也就没必要继续右移去做检查;同理pr
也无需继续左移。
- 每一步操作后都满足
- 指针
- 继续递归处理左右两个区间。
- 递归终止条件是
l >= r
,意味着区间里没有数或只有一个数。 - 递归终止条件满足时,排序已完成。
- 递归终止条件是
|
|
边界点分析:
- 原区间包含两个数
[1, 2]
,递归区间就是[l, pr]
对应[pr+1, r]
,此时pivot
不能取到右边界r
,pivot = nums[(l+r)/2]
;- 若取到右边界 1(
(l+r+1)/2 == 1
),此时pivot == 2
; - 初始时,
l == 0
,r == 1
; - 第一次递归前,
pl == 1
,pr
未移动,pr == 1
(不满足pl < pr
,两个数无需交换); - 接着进行递归,
qs(nums, 0, 1)
导致了死循环,而qs(nums, 2, 1)
没有问题。
- 若取到右边界 1(
- 原区间包含两个数
[1, 2]
,递归区间就是[l, pl-1]
对应[pl, r]
,此时pivot
不能取到左边界r
,pivot = nums[(l+r+1)/2]
。- 若取到左边界 0(
(l+r)/2 == 0
),此时pivot == 1
; - 初始时,
l == 0
,r == 1
; - 第一次递归前,
pl
未移动,pl == 0
,pr == 0
(不满足pl < pr
,两个数无需交换); - 接着进行递归,
qs(nums, 0, -1)
没问题,而qs(nums, 0, 1)
就导致了死循环。
- 若取到左边界 0(
快速选择算法(第 k 个数)利用快速排序算法的思想,每次只需要选半边递归。
|
|
References