“使用C ++编程原理和实践”中的一项练习要求实现STL binary_search()
函数。我使用递归来做到这一点,但是程序不断抛出异常。因此,我决定研究解决方案,而我的实现只缺少一件事。不幸的是,我不明白为什么会这样。
/* binary search for containers with random_access_iterators */
template<class Iter, class T>
bool binary(Iter first, Iter last, const T& val)
{
if (first == last) return false;
Iter middle = first + (last - first) / 2;
if (val == *middle) return true;
if (*middle < val /*??=>*/&& middle+1!=last/*<=??*/) return binary(middle, last, val);
if (*middle > val) return binary(first, middle, val);
return false;
}
为什么添加了middle+1!=last
?它是做什么的?
答案 0 :(得分:1)
在二进制搜索的特定实现中这是特例。在此处添加它是为了使binary
总是终止。
第二条if
语句总是使间隔更短,因为middle
总是严格小于last
。
但是,第一个if
有时可以使用相同的参数调用binary
。具体来说,如果first == middle
可能会发生这种情况。如果last - first <= 1
,可能会发生这种情况。如果last - first == 1
(如果是last - first == 0
,则已经单独处理了)。如果middle + 1 == last
,就会发生这种情况。
因此,作者决定单独处理该案。如果发生这种情况,并且*middle < val
,那么我们必须返回false
,这恰恰是在该特定实现中将发生的情况:第二个if
失败了,最后一个return false
起作用了。 / p>
这里是相同的代码,为了更好的清晰度(恕我直言)而重写:
template<class Iter, class T>
bool binary(Iter first, Iter last, const T& val)
{
if (first == last) return false;
Iter middle = first + (last - first) / 2;
if (*middle < val) {
if (last - first == 1) {
return false;
} else {
// first < middle
return binary(middle, last, val);
}
} else if (*middle == val) {
return true;
} else {
// *middle > val
return binary(first, middle, val);
}
}
我个人认为该解决方案不是优雅的,部分原因是由于这种奇怪的特殊情况,如果以稍微不同的方式重写该函数,则可以避免。
例如,一个改进(众多)中的一个改进是从(middle + 1, last)
进行第一个递归调用-作为*middle < val
,将middle
包含在我们的搜索范围内毫无意义。这也保证了终止
template<class Iter, class T>
bool binary(Iter first, Iter last, const T& val)
{
if (first == last) return false;
Iter middle = first + (last - first) / 2;
if (*middle < val) {
return binary(middle + 1, last, val);
} else if (*middle == val) {
return true;
} else {
// *middle > val
return binary(first, middle, val);
}
}