C ++ std :: lower_bound和std :: set :: lower_bound之间的区别?

时间:2015-08-05 01:24:48

标签: c++ algorithm c++11 std binary-search

最近,在处理C ++中的编程问题时,我遇到了一些有趣的东西。我的算法使用了一个非常大的集合,并且会在其上使用std :: lower_bound很多次。然而,在提交我的解决方案之后,与我在纸上做的数学证明我的代码足够快,它最终变得太慢了。代码看起来像这样:

using namespace std;

set<int> s;
int x;

//code code code

set<int>::iterator it = lower_bound(s.begin(),s.end(),x);

然而,在从一个伙伴那里得到一个使用set :: lower_bound的提示之后,所讨论的算法比以前更快地工作了waaaaaaaay,它跟着我的数学。更改后的二进制搜索:

set<int>::iterator it = s.lower_bound(x);

我的问题是这两者之间的区别是什么?为什么一个人工作得多,比另一个人快得多?是不是low_bound应该是具有复杂度O(log2(n))的二元搜索函数?在我的代码中,它最终比那更慢。

4 个答案:

答案 0 :(得分:3)

std::set通常实现为自平衡树,其中包含一些类似列表的结构。知道了这个结构,std::set::lower_bound将遍历,知道树结构的属性。这里的每一步都意味着遵循左或右子分支。

std::lower_bound需要运行类似于对数据进行二进制搜索的操作。但是,由于std::set::iterator是双向的,因此速度要慢得多,需要在已检查的元素之间进行大量增量。因此,元素之间的工作更加激烈。在这种情况下,算法将检查A和B之间的元素,然后调整A或B中的一个,找到它们之间的元素,然后重复。

答案 1 :(得分:1)

std::lower_bound泛型二进制搜索算法,适用于大多数STL容器。 set::lower_bound旨在与std::set一起使用,因此它利用了std::set的独特属性。

由于std::set通常被实现为红黑树,可以想象std::lower_bound遍历所有节点,而set::lower_bound只是遍历树。

答案 2 :(得分:1)

std::lower_bound始终保证O(log n) 比较,如果传递O(log n),则只保证RandomAccessIterator时间,而不仅仅是ForwardIterator它不提供常数时间std::advance

同一算法的std::set::lower_bound实现能够使用结构的内部细节来避免这个问题。

答案 3 :(得分:1)

阅读std:lower_bound的API后: std:lower_bound

  

在非随机访问迭代器上,迭代器进展产生了平均N的额外线性复杂度。

我认为STL集正在使用非随机访问迭代器,因此如果在STL集上使用它不会进行O(lg N)二进制搜索