Hoare快速排序的Partition实现
伪代码
// 升序
Hoare_Partition(A, L, R)
x = A[L]
i = L, j = R
while i < j // 循环一
while i < j and A[j] <= x // 循环二
j--
while i < j and A[i] >= x // 循环三
i++
if i < j
exchange A[j] with A[i] // 交换一
exchange A[L] with A[i] // 交换二
return i
解释
以升序算法为例。
目的:返回一个数组下标 i
,保证 A[L, L+1, ..., i-1] <= A[i]
,A[i+1, i+2, ..., R] >= A[i]
。
思想:双指针
x
:参考值(x = A[L]
)j
:从右往左遍历,寻找小于x
的A[j]
i
:从左往右遍历,寻找大于x
的A[i]
交换
:若满足(i < j
),则交换A[j]
和A[i]
。此操作保证大于x
的元素在数组右侧,小于x
的元素在数组左侧。(交换后,A[L, L+1, ..., i] <= x
,A[j, j+1, ..., R] >= x
)
注意
约定
:如伪代码中注释所写,对各个循环和交换操作取一个名称。
1. 循环结束的两种情况:
i -> j
x = 5
5 3 4 2 7 5
^ ^
i j(已结束)
j
已结束循环二,即此时 A[j] < x
。
i
从 3
开始遍历,直至 i == j
,结束循环三。因不满足交换一的条件,所以结束循环一。
此时,A[i]
必然小于 x
,未达到算法的目的。因此,进行交换二,使 A[i] == x
,则达成目的。
j -> i
5 4 3 7 10 5
^ ^
(已结束)i j
i
已结束循环三,(因为 j
先遍历,所以)此时已经结束一轮循环(执行过交换一),A[i]
必然小于 x
。
j
从 10
开始遍历,直至 i == j,结束循环三。因不满足交换一的条件,所以结束循环一。
显然,A[i] < x
。因此,进行交换二,使 A[i] == x,则达成目的。
2. 为什么要令 i = L
,且先遍历 j
?
答
:保证循环一结束时,满足以下三点:
- 条件一:
A[i] <= x
- 条件二:
A[L, L+1, ..., i-1] <= x
- 条件三:
A[i+1, i+2, ..., R] >= x
同时满足三个条件,在循环一结束后,执行交换二,则达到算法的目的。
反例:
1 2 3 4 5
^ ^
i j
- 假设一:
i = L + 1
循环一结束时,A[i] == 2 > x
,违背条件一。 - 假设二:优先遍历
i
循环一结束时,A[i] == 2 > x
,违背条件一。
3. 为什么三个循环结束的条件是 i < j
?
- 循环一:若
i == j
,则表明仅剩一个元素,自身就是排列好的。 - 循环二:该循环可以令
i <= j
- 循环三:防止循环一结束后出现
A[i] > x
反例:
x = 5
5 3 4 2 7 5
^ ^
i j(已结束)
若 i == j
仍执行循环三,则循环一结束时 A[i] == 7 > x
,违背条件一。
完