120

我需要一个与 C++ STL 容器兼容的二进制搜索算法,类似于std::binary_search标准库的<algorithm>标头中的内容,但我需要它返回指向结果的迭代器,而不是告诉我元素是否存在的简单布尔值。

(顺便说一句,标准委员会在为 binary_search 定义 API 时到底在想什么?!)

我主要关心的是我需要二进制搜索的速度,所以虽然我可以使用其他算法找到数据,如下所述,但我想利用我的数据已排序的事实来获得二进制的好处搜索,而不是线性搜索。

到目前为止lower_boundupper_bound如果缺少基准,则失败:

//lousy pseudo code
vector(1,2,3,4,6,7,8,9,0) //notice no 5
iter = lower_bound_or_upper_bound(start,end,5)
iter != 5 && iter !=end //not returning end as usual, instead it'll return 4 or 6

注意:只要它与容器兼容,我也可以使用不属于 std 命名空间的算法。比如说,boost::binary_search

4

9 回答 9

105

没有这样的功能,但您可以使用std::lower_bound,std::upper_bound或编写一个简单的功能std::equal_range

一个简单的实现可能是

template<class Iter, class T>
Iter binary_find(Iter begin, Iter end, T val)
{
    // Finds the lower bound in at most log(last - first) + 1 comparisons
    Iter i = std::lower_bound(begin, end, val);

    if (i != end && !(val < *i))
        return i; // found
    else
        return end; // not found
}

另一种解决方案是使用 a std::set,它保证元素的顺序并提供一种iterator find(T key)将迭代器返回给给定项目的方法。但是,您的要求可能与使用集合不兼容(例如,如果您需要多次存储相同的元素)。

于 2009-01-15T10:45:11.030 回答
10

你应该看看std::equal_range。它将返回一对迭代器到所有结果的范围。

于 2009-01-15T10:39:08.203 回答
6

其中有一组:

http://www.sgi.com/tech/stl/table_of_contents.html

搜索:

单独说明:

他们可能认为搜索容器可以得出多个结果。但是在您只需要测试是否存在的奇怪情况下,优化版本也会很好。

于 2009-01-15T10:41:28.743 回答
3

如果您不喜欢 std::lower_bound 太低级,您可能需要检查boost::container::flat_multiset。它是使用二进制搜索实现为排序向量的 std::multiset 的直接替代品。

于 2012-11-03T12:58:50.777 回答
3

最短的实现,想知道为什么它没有包含在标准库中:

template<class ForwardIt, class T, class Compare=std::less<>>
ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp={})
{
    // Note: BOTH type T and the type after ForwardIt is dereferenced 
    // must be implicitly convertible to BOTH Type1 and Type2, used in Compare. 
    // This is stricter than lower_bound requirement (see above)

    first = std::lower_bound(first, last, value, comp);
    return first != last && !comp(value, *first) ? first : last;
}

来自https://en.cppreference.com/w/cpp/algorithm/lower_bound

于 2018-09-25T12:26:27.050 回答
2
int BinarySearch(vector<int> array,int var)
{ 
    //array should be sorted in ascending order in this case  
    int start=0;
    int end=array.size()-1;
    while(start<=end){
        int mid=(start+end)/2;
        if(array[mid]==var){
            return mid;
        }
        else if(var<array[mid]){
            end=mid-1;
        }
        else{
            start=mid+1;
        }
    }
    return 0;
}

例子:考虑一个数组,A=[1,2,3,4,5,6,7,8,9] 假设你要搜索3的索引 最初start=0 and end=9-1=8 现在, 因为开始<=结束; 中=4;(array[mid] which is 5) !=3 现在,3 位于 mid 的左侧,因为它小于 5。因此,我们只搜索数组的左侧因此,现在 start=0 和 end=3; mid=2。由于数组[mid]==3,因此我们得到了要搜索的数字。因此,我们返回等于 mid 的索引。

于 2018-02-12T19:50:43.283 回答
1

检查此功能qBinaryFind

RandomAccessIterator qBinaryFind ( RandomAccessIterator begin, RandomAccessIterator end, const T & value )

对范围 [begin, end) 执行二分搜索并返回 value 出现的位置。如果没有出现 value,则返回 end。

[begin, end) 范围内的项目必须按升序排序;参见 qSort()。

如果多次出现相同的值,则可以返回其中任何一个。如果您需要更精细的控制,请使用 qLowerBound() 或 qUpperBound()。

例子:

QVector<int> vect;
 vect << 3 << 3 << 6 << 6 << 6 << 8;

 QVector<int>::iterator i =
         qBinaryFind(vect.begin(), vect.end(), 6);
 // i == vect.begin() + 2 (or 3 or 4)

该函数包含在作为Qt<QtAlgorithms>一部分的头文件中。

于 2009-01-15T11:02:20.357 回答
0

std::lower_bound() :)

于 2009-01-15T10:43:51.127 回答
0

返回范围内位置的解决方案可能是这样的,只使用迭代器上的操作(即使迭代器不算术它也应该工作):

template <class InputIterator, typename T>
size_t BinarySearchPos(InputIterator first, InputIterator last, const T& val)
{       
    const InputIterator beginIt = first;
    InputIterator element = first;
    size_t p = 0;
    size_t shift = 0;
    while((first <= last)) 
    {
        p = std::distance(beginIt, first);
        size_t u = std::distance(beginIt, last);
        size_t m = p + (u-p)/2;  // overflow safe (p+u)/2
        std::advance(element, m - shift);
        shift = m;
        if(*element == val) 
            return m; // value found at position  m
        if(val > *element)
            first = element++;
        else
            last  = element--;

    }
    // if you are here the value is not present in the list, 
    // however if there are the value should be at position u
    // (here p==u)
    return p;

}
于 2017-03-15T21:56:35.507 回答