我正在关于stackoverflow的帖子关于证明不同算法的正确性,他们似乎都是关于证明算法X或Y.我是计算机科学专业的学生,我意识到很多CS学生(包括我)都是挣扎于这个概念,我没有找到任何解释证明程序/算法正确性的一般方法的帖子。 Wiki和Youtube都没有真正帮助,因为两者关于当前主题的信息量非常有限。
你能逐步解释“通用”方法(如果有的话)来证明算法的正确性,解释循环不变量的方式,为什么它有时足以证明算法是部分正确而不是完全,包含所有细节和细微差别,而不会遗漏任何相关内容。只是为了确保任何人都能理解这个概念,让我们证明二进制搜索算法的正确性(以最通用的方式)。
int binSearch(int[] a, int x) {
int l = 0;
int r = a.length - 1;
int m = 0;
while (l <= r && a[m] != x) {
m = (l + r) / 2;
if (a[m] > x)
r = m - 1;
else if (a[m] < x)
l = m + 1;
}
if (a[m] == x)
return m
else
return -1;
答案 0 :(得分:1)
算法及其在特定编程语言中的实现之间存在差异。当你无法“证明”它是正确的时,完全可以正确地实现算法! (您可以编写正确的二进制搜索,而不必知道'为什么'它总是适用于排序列表。)
让我们为你的例子写出算法:二分搜索。
在 n 元素的排序列表中,搜索到的值 x 可能会出现在该列表中,也可能不会出现。
列表的“长度”,即 x 可能存在的界限,可以用索引 l 和 r <表示/ em>这样可以确保如果 x 在列表中,它将位于 l 和 r 之间的位置(包括)如果它不在这些值之间(再次,包括),它将不在整个列表中。对于排序的列表,这始终是正确的。提前检查可能是测试 x 是否低于第一个元素值或高于最后一个元素值;如果是这样,那就是“超出界限”,你就完成了。
如果由 l 和 r 绑定的列表片段的长度仅为1个元素,那么如果找到element[l] = x
的搜索值,否则它不在列表中。
如果列表片段的长度大于1,则在 l 和 r 之间选择一个随机元素(通常选择中点)。它的值可以小于,等于或大于 x 。
由于我们知道在排序列表中 x 可能位于 l 和 r 之间的任何位置(如果它在列表中),您可以更新 l 或 r (取决于步骤#2的结果)和整体声明 elem [l]&lt; = x&lt; = elem [r] 仍然是真的。其中一个 elem [l]&lt; = x&lt; = elem [m] 和 elem [m]&lt; = x&lt; = elem [r] 必须为true ,它决定了你可以移动的终点。
l 的每次更改都会将其移至 r ; r 的每次更改都会将其移至 l 。从步骤#1开始重复,直到间隔 l..r 只有1个元素长,因此步骤#1为true
。
由于每个比较必须将 l 或 r 更新为另一个,因此列表片段在每次迭代时都会变短。因此,从逻辑上讲,它的最终长度为1,步骤#1将停止算法,并且所选值将尽可能接近 x 的值(在某种意义上说, lower元素的值小于 x ,而较高元素的值大于 x 。)
这逐步描述了会发生什么,并且具有明确的停止状态,它将始终返回正确的结果。任何步骤都没有歧义 - 想要的元素 总是在 l 和 r 之间。
这是二进制搜索工作方式的逻辑证明(即,它将始终返回所需的结果),但二进制搜索只能 。其他算法需要不同的证明。
不知怎的,我得到了你正在寻找证明证明的想法:“证明不同算法的正确性”。这就是计算的圣杯。你应该阅读图灵的停止定理(如果我没记错的话,说明没有这样的事情)。