循环不变式
循环不变式
一、数学归纳法
因为循环不变式的定义与数学归纳法类似,所以我们先来看看数学归纳法。
我们首先从高中开始回忆起,有关于数列的数学归纳法。
一般的,证明一个与正整数
1. 归纳奠基:证明当
2. 归纳步骤:证明当
根据 1. 2. 两步,我们可以断定对于
对于上述的证明过程,我们称之为数学归纳法。
二、循环不变式
《算法导论》有关于循环不变式的定义[2]:
循环不变式主要用来帮助我们理解算法的正确性。关于循环不变式,我们必须证明三个性质:
1. 初始化:循环的第一次迭代之前,它为真。
2. 保持:如果循环的某次迭代之前它为真,那么下次迭代之前它仍为真。
3. 终止:在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法是正确的。
基于霍尔三元组的定义,我们可以将循环不变式中while的部分正确性可定义为[3]:
当前两条性质成立时,在循环的每次迭代之前,循环不变式都为真。(当然,为了证明循环不变式在每次迭代之前保持为真,我们完全可是使用不同于循环不变式本身的其他已证实的事实。)注意,这类似于数学归纳法,其中为了证明某条性质成立,需要证明一个基本情况和一个归纳步骤。这里,证明第一个迭代之前不变式成立对应于基本情况,证明从一次迭代到下一次迭代不变式成立对应于归纳步骤[2:1]。
第三条性质也是是最重要的,因为我们将使用循环不变式来证明正确性。通常,我们和导致循环终止的条件一起使用循环不变式。终止性不同于我们通常使用数学归纳法的做法,在归纳法中,归纳步是无限地使用得,这里当循环终止时,停止“归纳”[2:2]。
下面通过两个例子来说明循环不变式的使用。
三、循环不变式的使用
3.1 线性查找
本部分内容参考自知乎专栏《算法导论》——循环不变式[4]。
我们首先来看一个简单的例子,线性查找。线性查找的算法如下:
int LinearSearch(int A[], int n, int x)
{
for (int i = 0; i < n; i++)
{
if (A[i] == x)
return i;
}
return -1;
}
我们来证明这个算法的正确性。首先我们需要定义循环不变式,这里我们定义循环不变式为:
在每次迭代之前,如果
在 中,则 中的元素都不等于 。
接下来我们证明循环不变式的三条性质:
- 初始化:在第一次迭代之前,
,所以 为空,因此循环不变式成立。 - 保持:在第
次迭代之前,在数组 中找不到 ,所以 中的元素都不等于 ,因此循环不变式成立。 - 终止:
- 在第
次迭代时,找到了 ,所以 中的元素都不等于 ,因此循环不变式成立。- 更为详细的,
- I. 在第
次迭代时,找到了 ,所以对于 时, 中的元素都不等于 。则有 中的元素都不等于 。 - II.
, 由 2. 保持 ,所以 。
- 在第
次迭代时,没有找到 ,所以 中的元素都不等于 ,因此循环不变式成立。
综上所述,循环不变式成立,算法正确。
- 在第
3.2 插入排序
插入排序是个比较经典的排序算法,其算法过程为:
- 将第一个元素看作已排序的序列,将第二个元素到最后一个元素看作未排序的序列。
- 从未排序的序列中取出第一个元素,将其插入到已排序的序列中的合适位置。
- 重复步骤 2,直到未排序的序列为空。
通俗来说就是,每次从后面的未排序序列中取出一个元素,然后将其插入到前面的已排序序列中的合适位置。
插入排序的算法如下:
void InsertionSort(int A[], int n)
{
for (int i = 1; i < n; i++)
{
int key = A[i];
int j = i - 1;
while (j >= 0 && A[j] > key)
{
A[j + 1] = A[j];
j--;
}
A[j + 1] = key;
}
}
我们来证明这个算法的正确性。首先我们需要定义循环不变式,这里我们定义循环不变式为:
在每次迭代之前,
中的元素都是原来 中的元素,但已经按序排列。
接下来我们证明循环不变式的三条性质:
- 初始化:在第一次迭代之前,
,所以 只有一个元素,既 ,对于这一个元素,显然是已经按序排列的,因此循环不变式成立。 - 保持:对于for循环体的第一行,我们可以看到,每次迭代都会将
的值赋给 ,所以 中的元素都是原来 中的元素,但已经按序排列。接下来我们来看while循环体,while循环体的第一行是 ,这一行的作用是将 的值赋给 ,这样就将 向后移动了一位。为方便起见,我们统一用 表示,重述上一句话,也就是当第 时,将 的值不断向前移动。直到到达一个位置,是的这个移动的值大于前面的值。 - 终止:导致for循环结束的条件是
,那么对于 中的元素,均根据 “2. 保持”,已经按序排列,特别的 中的元素就是数组 的所有元素,因此循环不变式成立,算法正确。
以上就是我对于循环不变式的理解,如果有错误的地方,欢迎指正。
参考与注释:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)