目录
何为循环不变式
循环不变式 (loop invariant) 用于理解和证明算法的正确性。实际上,循环不变式并不是狭义上的式子,而是一个在算法起始、中间运算、中止的过程中保持为“真”的命题。即在循环体的每次执行前后均为真的谓词。循环不变式体现了循环程序中循环变量的变化规律。
理解循环不变式
举例说明:口袋中有黑、白两色小球,现将手放入袋中每次摸出两个,如果两球同色就都不放回袋中,如果两球异色就将白球放回,由于每次至少减少一个,所以袋中的球必然越来越少。现问:如果袋中最后剩下一个球,此球的颜色与开始时袋中黑、白球的个数有什么关系?按照一般的思路,此题非常复杂,难以解决。多次重复摸球及放回的动作构成了一个循环过程。如果我们有意识地寻找循环过程中不变的性质,就会发现,在循环过程中,白球个数的奇偶性保持不变,因为,每次取出的白球的个数或是零或是2。因此,如果开始时白球的个数为奇数,那么剩下的一球为白球。如果开始时白球的个数为偶数,那么剩下的一球为黑球。
这种不依较前面所执行的重复次数的性质称之为循环不变式。
循环不变式的性质
关于循环不变式,我们需要证明三条性质:
初始化:循环的第一次迭代之前,它为真。
保持:如果循环的某次迭代之前它为真,那么下次迭代之前它仍为真。
终止:在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法是否是正确的。
前两条性质有点类似于数学归纳法,但第三条性质与我们通常使用的数学归纳法不同,在归纳法中,归纳步是无限使用的,但在这里当循环终止时,停止“归纳”。
利用循环不变式分析插入排序
插入排序 (insertion sort) 是一种简单的排序算法,下面利用循环不变式证明插入排序的正确性。
插入排序的伪代码如下:
INSERTION-SORT(A)
for j = 2 to A.length
key = A[j]
//将A[j]插入到排序后的A[1..j-1]中
i = j - 1
while i > 0 and A[i] > key
A[i + 1] = A[i]
i = i - 1
A[i + 1] = key
首先,要先找出其中的循环不变式。经过分析,可以看出:在for循环的每次迭代开始时,子数组A[1..j-1]由原来在A[1..j-1]中的元素组成,但已按升序排列。
接着证明循环不变式的三条性质成立:
初始化:在循环的第一次迭代之前,子数组A[1..j-1]仅由第一个元素A[1]组成,循环不变式显然成立。
保持:在循环中,将A[ j - 1]、A[ j - 2]、A[ j - 3]等向右移动一个位置,直到A[j]找到适当位置,并将A[ j ]插入到该位置。此时子数组A[1.. j ]由原来在A[1.. j ]中的元素组成,但已按序排列。循环不变式成立。
终止:循环终止的条件为 j >A.length=n。即 j =A.length+1时。此时子数组A[1.. n ]由原来在A[1.. n ]中的元素组成,但已按序排列。循环不变式成立,算法正确。