STL binary_search()实现

时间:2018-06-23 18:42:34

标签: c++ algorithm binary-search

“使用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?它是做什么的?

1 个答案:

答案 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);
    }
}