循环不变式与插入排序证明
插入排序说明: 工作方式像排序一手扑克牌。开始时,左手为空并且桌子上的牌面向下。然后每次从桌子上拿走一张牌并将它插入左手中正确的位置。为了找到一张牌的正确位置,我们从右到左将它与自己手中的每张牌进行比较。
算法实现- 代码
INSERTION-SORT(A) A表示待排序的数组
for (int j = 1; j < array.length; j ++) {
int key = array[j];
// 将这张牌和手上的牌做比较 A[1...j-1]
int i = j - 1;
while (i >= 0 && array[i] > key) {
array[i + 1] = array[i];
i --;
}
array[i + 1] = key;
}
循环不变式
在for循环每次迭代开始,子数组A[1…j-1]由原来在A[1…j-1]中的元素组成,但已按序排序。我们把A[1…j-i]称为循环不变式。 循环不变式主要用来帮助我们理解算法的正确性。关于循环不变式,我们必须证明三条性质:
- 初始化:循环的第一次迭代之前,它为真。
- 保持:如果循环的某次迭代之前它为真,那么下次迭代之前它仍为真。
- 终止:在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法是正确的。
循环不变式插入排序正确性证明
-
初始化:第一次迭代之前,循环不变式成立。子数组A[1…j-1]仅由单个元素A[1]组成,该子数组是排序好的(只有一个元素,当然排序好的)。这表明第一次循环迭代之前,循环不变式成立。
-
保持:在while循环里面,我们将A[j-1]、A[j-2]、A[j-3]… 往后挪了一个位置,直到找到A[j]适当的位置,之后将A[j]插入该位置。子数组始终是 A[1…j-1],并已排序。那么for循环的下一次迭代增加j将保持循环不变式。
-
终止:首先终止条件是 j > A.length = n。因为每次循环迭代j加1,那么不终止的时候,必有 j = n + 1,而这个时候我们的子数组A[1…n]由原来的A[1…n]中的元素组成,并已排序。因此算法正确。
[1] 《算法导论》 机械工业出版社