【问题标题】:C++ Difference between std::lower_bound and std::set::lower_bound?c++ std::lower_bound 和 std::set::lower_bound 的区别?
【发布时间】:2015-10-27 14:32:38
【问题描述】:

最近,在处理 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);

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

【问题讨论】:

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


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    std::lower_bound 始终保证O(log n) 比较,如果通过RandomAccessIterator,则仅保证O(log n) 时间,而不仅仅是不提供恒定时间std::advanceForwardIterator .

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 哦,我明白了,谢谢大家向我解释。我会记得现在总是将 set::lower_bound 与集合一起使用
      【解决方案4】:

      看完std::lower_bound的API

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

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

      【讨论】:

      • 你是对的,std::set::iterator是双向的,不是随机访问
      猜你喜欢
      • 2011-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-26
      • 1970-01-01
      • 1970-01-01
      • 2012-02-05
      • 2017-08-30
      相关资源
      最近更新 更多