您当前的算法不正确,但您非常接近它。在这里,我将展示您的算法可能出错的地方。
考虑数组[3,2,1,2]
。
假设你先打电话FindMin(F, 0, 3)
FindMin(F, 0, 3)
--mid = 1
--检查 F[1] 错误
--检查 F[1] 为真,调用 FindMin(F, 1, 3)
----中 = 2
----检查 F[2] 为真,调用 FindMin(F, 1, 2)
------中= 1
------检查 F[1] 否
------检查 F[1] 为真,调用 FindMin(F, 1, 2)
--------中= 1
--------检查 F[1] 假
--------检查 F[1] 为真,调用 FindMin(F, 1, 2)
...这将永远持续下去,直到内存不足
您可以对其进行一些更改以使其正确:
FindMin(F, lo, hi){
if(lo==hi) return F[lo];
int mid = lo + (hi-lo)/2 // Actually you can change this into (lo+hi)/2
if(F[mid] > F[mid+1]) return FindMin(F, mid+1, hi) // Change the comparison and recursive call!
if(F[mid] > F[mid-1]) return FindMin(F, lo, mid-1) // Change the comparison and recursive call!
// If we reach here, that means F[mid-1] > F[mid] < F[mid+1]
return F[mid]
}
尽管正如@Joni 所说,您需要处理边界情况。只检查F[mid+1]
就可以了。我保证以下代码不会出现任何越界错误并且是正确的:
FindMin(F, lo, hi){
if(lo==hi) return F[lo]; // Line 1
int mid = (lo+hi)/2 // Line 2
if(F[mid] > F[mid+1]) return FindMin(F, mid+1, hi) // Line 3
else return FindMin(F, lo, mid) // Line 4
}
调用函数hi
作为数组中的最后一个索引
第 1 行是基本情况。
第 2 行计算中间索引。注意mid < hi
这里,sincemid == hi
暗示lo == hi
,这已经在第 1 行中介绍过。所以mid
永远不要指向数组中的最后一个索引。所以检查是安全的F[mid+1]
第 3 行检查是否F[mid] > F[mid+1]
,如果是,则F[mid]
不能是答案,因为它比某个数字大,而且F[lo..mid-1]
还会更大,所以答案必须在F[mid+1..hi]
. 所以打电话FindMin(F, mid+1, hi)
。请注意mid+1 > lo
,所以范围mid+1..hi
小于lo..hi
。
第 4 行:如果我们到达这里,这意味着F[mid] < F[mid+1]
. 所以答案可以在F[lo..mid]
. 所以打电话FindMin(F, lo, mid)
。请注意,因为mid < hi
,FindMin(F, lo, mid)
将不同于FindMin(F, lo, hi)
。更具体地说,范围减小,如第 3 行中的情况。
结合第 3 行和第 4 行,每次调用FindMin
都是以递减范围进行的,因此算法应该在一段时间后停止,这将在第 1 行中。