算法学习二:循环不变式证明算法的正确性

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mountzf/article/details/51866342

循环不变式证明算法的正确性

循环不变式主要用来辅助我们理解算法的正确性,对于循环不变式,必须证明它的三个性质(有些类似于数学归纳法的意味):

  • 初始化:它在循环的第一轮迭代开始之前,应该是正确的。
  • 保持:如果在某一次循环迭代开始之前是正确的,那么在下一次迭代开始之前,它也应该保持正确(假设当循环变量等于k时符合,再看执行一遍循环体后是否还符合循环不变式)。
  • 结束:当循环结束时,不变式给了我们一个有用的性质,它有助于表明算法是正确的(这一步是和数学归纳法不同的一点,用循环不变式则更进一步,数学归纳法到这里就得出了一个关系式就结束,而用循环不变式,不但要先确保一个正确的关系式,还要看最后循环结束时,循环变量最后等于多少,根据循环不变式推导是否符合自己的要求。)。

编写循环时,找到让每次循环都成立的逻辑表达式很重要。这种逻辑表达式称为循环不变式(loop invariant)。循环不变式相当于用数学归纳法证明的“断言”。循环不变式用于证明程序的正确性。在编写循环时,思考一下“这个循环的循环不变式是什么”就能减少错误。
注意:好像每个循环都可以找到一个循环不变式,并通过这个循环不变式证明循环迭代的正确性。

插入排序算法的证明

对照循环不变式的原理,下面来试着对插入排序算法的正确性进行论证。
插入算法及其实现在此已经讲过:

INSERTION_SORT(A) pseudocode
for j<--- 2 to length[A]
    do key<---A[j]
    //Insert A[j] into the sorted sequence A[1,2,...,j-1]
    i<---j-1
    while i>0 and A[i]>key
        do A[i+1]<---A[i] 
        i<---i-1
    A[i+1]<---key
  • 初始化:在第一轮迭代开始之前,证明其正确性。此时j=2,A[1…j-1]中只有一个元素A[1],显然,一个元素是已经排序的了。所以,证明了循环不变式在第一轮迭代之前是成立的。
  • 保持:接下来要证明在每轮迭代中,循环不变式保持成立。迭代之前,假设A[1…j-1]是已经排好序的序列,待排序的元素A[j]依次与A[j-1]、A[j-2]进行比较,如果A[j-1]等大于A[j],则依次将其向右移动一位A[i+1]<---A[i],当遇到开始小于A[j]的元素时,则A[j]找到了合适的插入位置,插入之后,整个序列又是排好序的了。即在假设j成立的情况下,j+1也成立,循环不变式在迭代过程中保持成立。
  • 终止:最后,分析一下循环结束时候的情况。当j=n+1时,循环结束,此时A[1…n]中已经有n个元素,且已经排好序,就是排好序的数组A[1…n],所以算法正确。

合并排序算法的证明

合并排序算法及其实现在此已经详细讨论过,下面试着利用循环不变式证明合并排序算法的正确性。

MERGE(A,p,q,r)
A[p,q]   n1<---q-p+1
A[q+1,r] n2<---r-q
//create arrays L[1,...,n1+1] and R[1,...,n2+1]
for i<---1 to n1
    L[i]<---A[p+i-1]
for j<---1 to n2
    R[j]<---A[q+j]
L[n1+1]<---∞
R[]n2+1<---∞
i<---1
j<---1
for k<---p to r
    do if L[i]<=R[j]
        then A[k]<---L[i]
            i<---i+1
        else A[k]<---R[j]
            j<---j+1

对于上述流程,我们需要证明,在第一轮迭代开始之前,这个循环不变式是成立的,且对于每一次迭代都能够使该循环不变式保持成立,并证明在循环终止时算法的正确性。

  • 初始化:循环开始之前,k=p,此时A中有k-p=0个元素,显示算是有序的,所以迭代之前循环不变式成立。
  • 保持:假设k的时候循环不变式成立,即A[1…k]是已经排序好的序列,则A[1…k]中的任何元素不大于L[i]和R[j]。对于k+1,假设L[i]<R[j],则A[k+1]=L[i]>max{A[1...k]},此时A[1…k,k+1]又是一个有序的序列。即在迭代过程中,循环不变式保持成立。
  • 终止:当k=r+1时,循环终止,A[p,k-1]中已经包含A[p,r],序列A中所有的元素都已经被复制回A中并排好序。所以算法终止时,得到的是一个已经排好序的序列A。

循环不变式是算法设计与论证中十分重要的基础知识,这里的两个排序算法都非常简单,所以没有真正体现出循环不变式的威力来,而是仅仅作为循环不变式的入门引导例子。随着后面算法理论的学习,遇到真正能让我们见识到其威力的例子的时候再和大家分享。

祝枫
2016年7月9日于深圳

没有更多推荐了,返回首页