如何找到循环不变量并证明正确性?

时间:2013-12-03 17:10:26

标签: algorithm loops proof loop-invariant proof-of-correctness

int i, temp; 
a is an array of integers [1...100] 

i = 1; 

while i < 100 
    if a[i] > a[i+1] 
        temp = a[i]
        a[i] = a[i+1]
        a[i+1] = temp 
    i = i+1

我无法理解如何找到循环不变量并为它们编写正式语句。因此,循环不变量只是在循环的每次迭代之前和之后立即生效的条件。看起来代码正在进行交换:如果数组中的以下元素大于当前元素,则切换位置。我的意思是从循环不变量的定义,它真的听起来像是我&lt; 100因为循环运行必须是真的,但我真的不明白。非常感谢一些澄清。

4 个答案:

答案 0 :(得分:2)

按照你的定义,我可以看到两个循环不变条件:

1. i < 100
2. a[i] = greater than a[j] for all j < i, where i is the loop variable.

这实际上是冒泡排序的一个外循环迭代。在这个循环结束时,数组中的最高值冒泡到顶部(a [100])

答案 1 :(得分:1)

粗略地说,你是对的。循环不变是&#34;只是在循环的每次迭代之前和之后都是真的条件。&#34;但是,根据这个定义,对于所讨论的代码,实际上存在无数个循环不变量,并且大多数循环不变量并不特别令人感兴趣。例如,i&lt; 101,i&lt; 102,i&lt; 103,...都是给定代码的循环不变量。

然而,通常我们只是为了找到一个循环不变量而只是简单地找到一个循环不变量。相反,我们有兴趣证明一个程序是正确的,如果我们想要证明一个程序是正确的,那么一个精心选择的循环不变量就会变得非常有用。

例如,有问题的代码是冒泡排序算法的内部循环,其目的是使数组&#34;更多排序&#34;。因此,为了证明这个代码的完全正确性,我们必须证明三件事:

(1)当执行到达代码的末尾时,数组是代码开头的数组的排列。 (2)当执行到达代码的末尾时,数组中的反转次数为零或者小于代码开头的数组中的反转次数(这个条件有助于我们证明外部冒泡排序算法的循环终止)。 (3)代码终止。

为了证明(1)我们需要考虑三个执行路径(当我们考虑PATH 2时,循环不变将发挥关键作用。)

(路径1)考虑当代码开始时执行并首次到达循环顶部时会发生什么。由于在此执行路径上没有对数组执行任何操作,因此该数组是代码开头的数组的排列。

(路径2)现在考虑当执行从循环顶部开始,绕过循环并返回到循环顶部时会发生什么。如果a [i]&lt; = a [i + 1]则交换没有发生,因此,数组仍然是代码开头的数组的排列(因为没有对它进行任何操作)。或者,如果a [i]> a [i + 1]然后交换确实发生。但是,该数组仍然是代码开头的数组的排列(因为交换是一种排列)。因此,每当执行到达循环的顶部时,该数组就是代码开头的数组的排列。注意,语句&#34;数组是代码开头的数组的排列&#34;是我们需要帮助我们证明代码是正确的精心选择的循环不变量。

(路径3)最后,考虑一下当循环顶部的执行开始但没有进入循环时会发生什么,而是转到代码的末尾。由于在此执行路径上没有对数组执行任何操作,因此该数组是代码开头的数组的排列。

这三条路径涵盖了从代码开始到代码结束执行的所有可能方式,因此,我们已经证明(1)代码末尾的数组是数组的排列在代码的开头。

答案 2 :(得分:0)

  

循环不变量是一种适用于每一个的谓词(条件)   循环的迭代,在之前和之前必然是真的   每次迭代循环后立即。

当然可以有无限多的循环不变量,但是循环不变属性用于证明算法的正确性这一事实限制了我们只考虑所谓的有趣循环不变量&#34;。

您的程序,其目的是对给定的数组进行排序,是一个简单的冒泡排序。

Goal Statement: The array a is sorted at the end of while loop
Some interesting properties can be like: At the end of ith iteration, a[0:i] is sorted, which when extended to i=100, results in the whole array being sorted.

Loop Invariant for your case: a[100-i: 100-1] is sorted

请注意,当i等于100时,上述语句将意味着整个数组已排序,这是您希望在算法结束时成为现实的数组。

PS:刚刚意识到这是一个老问题,无论如何都有助于提高我的回答技巧:)

答案 3 :(得分:-1)

您的循环由测试i < 100控制。在循环体内,i用于多个地方,但仅在一个地方分配。赋值总是发生,并且对于允许进入循环的任何i值,赋值将收敛到终止条件。因此保证循环终止。

至于程序的正确性,这是一个不同的问题。根据您的阵列是使用从零开始还是基于一的索引,您使用i进行数组访问的方式可能会有问题。如果它是从零开始的,那么你永远不会看第一个元素,并且在最后一次迭代时你会用a[i+1]跳出界限。