如何证明算法的正确性?
2018-04-02 17:04
309 查看
结合算法导论相关章节的学习,利用号循环不变式可以帮助我们理解算法的正确性。循环不等式主要满足以下的三条性质:
初始化:循环的第一次迭代之前,它为真。
保持:如果循环的某次迭代之前它为真,那么下次迭代之前它仍为真
终止:在循环终止之前,不变式为我们提供一个有用的性质,该性质有助于证明算法是正确的。
接着使用循环不变式来证明正确性:
初始化:先证明在第一次循环迭代之前,循环不等式成立(j = 2)。所以子数组A[1…j-1]仅有单个元素A[1]组成,实际上就是A[1]中原来的元素。该元素只有一个且已经排好序。这表明第一次循环迭代之前循环不变式成立。
保持:接着处理第二条性质:证明每次迭代保持循环不等式。非形式化地,for循环体中的第4-7行将A[j-1]、A[j-2]、A[j-3]等向后移动一个位置,直到找到A[j]的适当位置,第8行将A[j]的值插入到该位置。此时,整个子数组A[1…j]由原来的A[1…j]中的元素组成,但已按序排列,那么对于for循环的下一次迭代将怎加j保持循环不变式。
终止:最后研究在循环终止时发生了什么。导致for循环终止的条件是j>A.length=n。因此为每次循环迭代j增加1,那么必有j = n+1。在循环不变式的表述中将j用n+1代替,我们有:子数组A[1…n]由原来在A[1…n]中的元素组成,但都已经按序排列。A[1…n]已经是整个数组故算法正确。
我们必须证明第12-17行for循环的第一次迭代之前该循环不变式成立,该循环的每次迭代保持该不变式,并且循环终止时,该不变式提供一种有用的性质来证明正确性。
初始化:循环的一次迭代之前,有k=p,所以子数组A[p…k-1]为空。这个空的子数组包含L和R的k-p=0个最小元素。又因为i=j=1,所以L[i]和R[j]都是各自所在数组中未被赋值回数组A的最小元素。
保持:为方便理解,假设L[i] <= R[j]。这时,L[i]是未被复制回数组A的最小元素。因为A[p..k-1]包含k-p个最小元素,所以在第14行将L[i]复制到A[k]之后,子数组A[p..k]将包含k-p+1个最小元素,增加k的值和i的值,为下次迭代重新建立该循环不等式,反之,若L[i] > R[j],则根据16-17行执行适当的操作来维持该循环不等式。
终止:终止时k = r+1。根据循环不等式,子数组A[p..k-1]就是A[p..r]且按从小到大的顺序包含L[1..n1+1]和R[1..n2+1]中的k-p=r-p+1个最小元素。数组L和R一起包含n1 + n2 + 2 = r - p + 3个元素。除两个最大元素以外,其它所有元素都已经被复制回数组A。
初始化:循环的第一次迭代之前,它为真。
保持:如果循环的某次迭代之前它为真,那么下次迭代之前它仍为真
终止:在循环终止之前,不变式为我们提供一个有用的性质,该性质有助于证明算法是正确的。
插入排序算法正确性
INSERTION-SORT(A) for j = 2 to A.length key = A[j] i = j - 1 while i > 0 and A[i] > key A[i+1] = A[i] i = i - 1 A[i+1] = A[j]
接着使用循环不变式来证明正确性:
初始化:先证明在第一次循环迭代之前,循环不等式成立(j = 2)。所以子数组A[1…j-1]仅有单个元素A[1]组成,实际上就是A[1]中原来的元素。该元素只有一个且已经排好序。这表明第一次循环迭代之前循环不变式成立。
保持:接着处理第二条性质:证明每次迭代保持循环不等式。非形式化地,for循环体中的第4-7行将A[j-1]、A[j-2]、A[j-3]等向后移动一个位置,直到找到A[j]的适当位置,第8行将A[j]的值插入到该位置。此时,整个子数组A[1…j]由原来的A[1…j]中的元素组成,但已按序排列,那么对于for循环的下一次迭代将怎加j保持循环不变式。
终止:最后研究在循环终止时发生了什么。导致for循环终止的条件是j>A.length=n。因此为每次循环迭代j增加1,那么必有j = n+1。在循环不变式的表述中将j用n+1代替,我们有:子数组A[1…n]由原来在A[1…n]中的元素组成,但都已经按序排列。A[1…n]已经是整个数组故算法正确。
归并排序算法正确性
MERGE(A,p,q,r) n1 = q - p + 1 n2 = r - q 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 if L[i] <= R[j] A[k] = L[i] i = i + 1 else A[k] = R[j] j = j + 1
我们必须证明第12-17行for循环的第一次迭代之前该循环不变式成立,该循环的每次迭代保持该不变式,并且循环终止时,该不变式提供一种有用的性质来证明正确性。
初始化:循环的一次迭代之前,有k=p,所以子数组A[p…k-1]为空。这个空的子数组包含L和R的k-p=0个最小元素。又因为i=j=1,所以L[i]和R[j]都是各自所在数组中未被赋值回数组A的最小元素。
保持:为方便理解,假设L[i] <= R[j]。这时,L[i]是未被复制回数组A的最小元素。因为A[p..k-1]包含k-p个最小元素,所以在第14行将L[i]复制到A[k]之后,子数组A[p..k]将包含k-p+1个最小元素,增加k的值和i的值,为下次迭代重新建立该循环不等式,反之,若L[i] > R[j],则根据16-17行执行适当的操作来维持该循环不等式。
终止:终止时k = r+1。根据循环不等式,子数组A[p..k-1]就是A[p..r]且按从小到大的顺序包含L[1..n1+1]和R[1..n2+1]中的k-p=r-p+1个最小元素。数组L和R一起包含n1 + n2 + 2 = r - p + 3个元素。除两个最大元素以外,其它所有元素都已经被复制回数组A。
相关文章推荐
- 贪心算法正确性证明(转载from刘子韬)
- 迪杰斯特拉(Dijkstra)算法描述及其正确性证明
- 有向图Kosaraju算法的正确性证明
- 贪心算法正确性证明
- LCS(最长公共子序列)动规算法正确性证明
- 证明增广路算法的正确性及dinic算法的使用
- 何谓最优算法?如何证明一个算法是最优的
- [原]关于对求两个排序数组交集的扫描算法正确性的证明
- 一道博弈的面试题及其算法正确性证明
- 证明求解约瑟夫斯问题的二进制左循环算法的正确性
- 部分背包问题的贪心算法正确性证明
- 区间树中区间重叠检测算法正确性的证明
- 【HDU4313】Matrix 多校 解题报告+AC代码+思路+算法正确性证明,此为Kruskal贪心简单版本,恶心版本稍后放出【目标达成 0.2%】
- 【HDU4313】Matrix 多校 解题报告+AC代码+思路+算法正确性证明,此为Kruskal贪心恶心版本,非自虐倾向慎入!建议想找解题报告的童鞋看简单版本的,这个我写给自己【目标达成 0.2%】
- 关于最大流增广路径算法的正确性的证明
- 【图论】【二分图匹配】匈牙利算法正确性证明所需的两个定理证明
- 如何理解算法的正确性
- 部分背包问题的贪心算法正确性证明
- 关于时间安排贪心算法正确性的证明
- 证明增广路算法的正确性