我正在阅读此post并尝试弄清楚如何确定二元搜索的不变关系。具体来说,在他给出的两个例子中,为什么这两个不变的关系是不同的?是什么让它与众不同?
A部分[开始]<目标< [结束]很明显,但问题是在哪里放置=符号?
另一个问题是,我可以简单地将框架更改为:
int binarySearchFramework(int A[], int n, int target) {
int start = start index of array - 1;
int end = length of the A;
while (end - start > 1) {
int mid = (end - start) / 2 + start;
if (A[mid] == target) return mid;
if (A[mid] < target) {
end = mid;
} else {
start = mid;
}
}
//not found
...
}
这个不如帖子中提供的那个好吗?
非常感谢!
答案 0 :(得分:3)
你可以选择不变量。这是从实践中学到的技能。即使有经验,它通常也会涉及一些反复试验。选一个。看看它如何。寻找机会选择一个需要较少维护工作的机会。您选择的不变量可以对代码的复杂性和/或效率产生重大影响。
二元搜索中至少有四个合理的不变量选择:
a[lo] < target < a[hi]
a[lo] <= target < a[hi]
a[lo] < target <= a[hi]
a[lo] <= target <= a[hi]
你通常会看到最后一个因为它是最容易解释的,并且不涉及使用超出范围的数组索引进行棘手的初始化,而其他人则这样做。
现在 是使用a[lo] < target <= a[hi]
等不变量的理由。如果您希望始终在目标的重复系列中找到,则此不变量将执行O(log n)时间。当hi - lo == 1
时,hi
指向第一次出现的目标。
int find(int target, int *a, int size) {
// Establish invariant: a[lo] < target <= a[hi] || target does not exist
// We assume a[-1] contains an element less than target. But since it is never
// accessed, we don't need a real element there.
int lo = -1, hi = size - 1;
while (hi - lo > 1) {
// mid == -1 is impossible because hi-lo >= 2 due to while condition
int mid = lo + (hi - lo) / 2; // or (hi + lo) / 2 on 32 bit machines
if (a[mid] < target)
lo = mid; // a[mid] < target, so this maintains invariant
else
hi = mid; // target <= a[mid], so this maintains invariant
}
// if hi - lo == 1, then hi must be first occurrence of target, if it exists.
return hi > lo && a[hi] == target ? hi : NOT_FOUND;
}
注意,此代码未经测试,但应该由不变逻辑工作。
两个<=
的不变量只会找到目标的某些实例。你无法控制哪一个。
此不变 需要使用lo = -1
进行初始化。这增加了证明要求。您必须证明mid
永远不能设置为-1
,这会导致超出范围的访问权限。幸运的是,这个证据并不难。
你引用的文章很差。它有几个错误和不一致。寻找其他地方的例子。编程珍珠是一个不错的选择。
您建议的更改是正确的,但可能会有点慢,因为它取代了一次只运行一次的测试,每次迭代运行一次。
答案 1 :(得分:1)
问题的答案是问题的答案&#34;什么是循环不变量&#34;。
循环不变量的要点是在循环终止之前,期间和(可能最重要的)之后提供有用的属性。作为示例,插入排序具有循环不变量,即要排序的数组按照从1索引开始的范围的排序顺序(一个项始终排序),并且增长为整个数组。 这有用的是,如果在循环开始之前它是真的,并且循环没有违反它,你可以正确地推断出在执行循环之后整个数组都被排序了。假设你并没有弄乱你的终止条件,它没有违反循环不变量,因为不变量只是指整个数组的子数组,可能是也可能不是整个数组。如果提前终止,则子数组小于整个数组,但保证子数组按照不变量进行排序。
你链接的帖子说的大致相同,但如果作者真正解释了他所谈论的内容可能会更好。这篇文章似乎试图教导,但仍然没有说出应该说的,即使只是为那些好奇或需要更多信息的人提供更深入的信息的脚注。
回答你的问题&#34;为什么两个不变量不同&#34;直接,答案是因为他们正在解决两个不同的问题。
链接中的几个引用说明了这一点:
答案 2 :(得分:-1)
你写了
A部分[开始]&lt;目标&lt; [结束]很明显
但显然是错误的,因为初始值应该是start = 0,end = N-1(不是-1,N)。顺便说一句,对于链接中描述的情况(不同元素的数组),您不需要任何不变量。
这将毫无问题且易于理解。
int arr[] = {0,1,2,3,4,5,6,7};
int N = sizeof (arr) / sizeof (arr[0]);
int target = 4;
int l = 0, r = N-1;
while( l <= r ) {
int mid = (l+r)>>1;
if( arr[mid] == target )
return mid;
if( arr[mid] < target )
l = mid + 1;
else
r = mid - 1;
}
return -1; // not found