排序算法之:循环不变式在快速排序中的正确性证明
字数 1432 2025-10-30 17:43:25
排序算法之:循环不变式在快速排序中的正确性证明
题目描述
使用循环不变式(Loop Invariant)来证明快速排序(QuickSort)在划分(Partition)过程中的正确性。具体来说,需要证明在划分过程的每一步中,数组元素都能被正确地重新排列,使得所有小于主元(pivot)的元素位于主元左侧,所有大于主元的元素位于主元右侧。
解题过程
-
理解划分过程的目标
快速排序的划分步骤选取一个主元(例如数组最后一个元素),并重新排列数组,使得:- 主元被放置到其最终排序位置。
- 主元左侧的所有元素 ≤ 主元。
- 主元右侧的所有元素 ≥ 主元。
循环不变式需确保这一目标在划分过程中逐步达成。
-
定义循环不变式
在划分算法的循环中(例如Lomuto划分方案),定义以下不变式:- 设数组区间为
[low, high],主元为arr[high]。 - 循环变量
i表示当前小于等于主元的子数组的末尾索引(初始为low-1)。 - 循环变量
j用于遍历数组(初始为low)。
循环不变式: - 对于任意索引
k:- 若
low ≤ k ≤ i,则arr[k] ≤ pivot。 - 若
i+1 ≤ k ≤ j-1,则arr[k] > pivot。 - 若
k = high,则arr[k] = pivot(主元未被移动)。
- 若
- 区间
[j, high-1]为尚未处理的元素。
- 设数组区间为
-
初始状态验证
- 初始时
i = low-1,j = low。 - 区间
[low, i]为空,满足“所有元素 ≤ pivot”。 - 区间
[i+1, j-1]为空(因为j-1 = low-1),满足“所有元素 > pivot”。 - 区间
[j, high-1]包含全部待处理元素。
结论:循环不变式在初始状态下成立。
- 初始时
-
循环迭代维护不变式
遍历过程中,对于每个j:- 情况1:若
arr[j] ≤ pivot,则i增加1,交换arr[i]和arr[j]。- 交换后,
arr[i](原arr[j])≤ pivot,区间[low, i]仍满足条件。 - 原
arr[i](交换后位于j)可能 > pivot,但此时j已递增,该元素被纳入区间[i+1, j-1](大于pivot的区间)。
- 交换后,
- 情况2:若
arr[j] > pivot,仅递增j。- 元素
arr[j]自动落入区间[i+1, j-1](大于pivot的区间)。
- 元素
- 主元始终位于
high未被移动。
结论:每次迭代后,不变式仍然保持成立。
- 情况1:若
-
终止条件与正确性
- 循环终止时
j = high,此时区间[j, high-1]为空,所有元素已处理。 - 根据不变式:
[low, i]的元素 ≤ pivot。[i+1, high-1]的元素 > pivot。
- 最后交换
arr[i+1]和arr[high],将主元放置到正确位置i+1。 - 最终数组满足:
[low, i]≤ pivot,arr[i+1] = pivot,[i+2, high]≥ pivot。
结论:划分正确性得证。
- 循环终止时
-
总结
循环不变式通过明确循环各阶段的元素状态,确保了划分过程的正确性。这一方法可推广至其他排序算法的证明中,强调算法设计中不变式的重要性。