最近在看《算法导论》这本书,在它的第二章出现了一个很是有意思的概念——循环不变式(Loop Invariant)。一言以蔽之,提出循环不变式的目的是为了从理论上证实某个算法是正确的。算法
说实话我之前没有思考过这个问题。习惯养成的缘由,我在调试代码时,老是试各类各样的输入和查看对应的输出以保证整个程序是正确的。并非说这样是错误的,而是指这个习惯让我没有去思考从理论上证实算法正确性这条路。若是只是盲目地多试几个输入的话,就好像让电脑用算术去证实哥德巴赫猜测同样,是很是不优雅的。你能够证实很是大的数知足哥德巴赫猜测,但你永远也没法说哥德巴赫猜测是对的。数组
其实从理论上证实算法的正确性简单得使人惊讶,这个过程跟数学概括法一模一样。 咱们先来看看数学概括法是怎样的。oop
数学概括法有这么两步spa
咱们来举个例子调试
等差数列求和公式如何进行求证呢?code
验证该公式在
时成立。即有左边
,右边=
,因此这个公式在
时成立。排序
须要证实假设
时公式成立,那么能够推导出
时公式也成立。步骤以下:get
- 假设
时公式成立,即
(等式1)
- 而后在等式两边同时分别加上
获得
(等式2) 这就是
时的等式。咱们下一步须要根据 等式1证实 等式2 成立。经过因式分解合并,等式2的右边
也就是
这样咱们就完成了由
成立推导出
成立的过程,证毕。数学
结论:对于任意天然数n,公式均成立。it
那么接下来就让咱们用相似于数学概括法证实公式的方法来证实循环不变式以证实算法的正确性。
咱们以插入排序为例子(升序,在这里用伪代码来表示,数组的下标是):
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] = key
复制代码
就好像这样的公式同样,在此咱们能够为插入排序提出一个循环不变式:在每次for循环迭代开始以前,子数组
仍是原来位置在
的元素而且已经排好序了。
那么就跟数学概括法证实公式同样,咱们须要两步来证实它的正确性:
但由于咱们须要循环不变式来证实算法的正确性,咱们须要着重看循环结束时的状况,那么就引出了咱们须要证实循环不变式的第三个性质:
那么让咱们来看看是怎样具体证实的:
你会发现利用循环不变式来证实算法的正确性是如此得简单和优雅。