[英]C++ Difference between std::lower_bound and std::set::lower_bound?
最近,在处理 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)) 的二分查找函数吗? 在我的代码中,它最终比这慢得多。
std::set
通常被实现为一个自平衡树,其中包含一些类似列表的结构。 知道这个结构, std::set::lower_bound
将遍历树,知道树结构的属性。 这其中的每一步都意味着遵循左子分支或右子分支。
std::lower_bound
需要对数据运行类似于二进制搜索的东西。 但是,由于std::set::iterator
是双向的,因此速度要慢得多,需要在检查元素之间进行大量增量。 因此,元素之间所做的工作更加激烈。 在这种情况下,算法将检查 A 和 B 中间的元素,然后调整 A 或 B 之一,找到它们中间的元素,然后重复。
阅读std::lower_bound的 API 后
在非随机访问迭代器上,迭代器前进平均会产生 N 中的额外线性复杂度。
而且我认为 STL 集使用的是非随机访问迭代器,因此如果在 STL 集上使用,它不会进行 O(log N) 二进制搜索
std::lower_bound
是一种通用的二分搜索算法,适用于大多数 STL 容器。 set::lower_bound
旨在与std::set
因此它利用了std::set
的独特属性。
由于std::set
通常被实现为一棵红黑树,因此可以想象std::lower_bound
遍历所有节点,而set::lower_bound
只是向下遍历树。
std::lower_bound
始终保证O(log n)
比较,如果传递RandomAccessIterator
,则仅保证O(log n)
时间,而不仅仅是不提供恒定时间std::advance
的ForwardIterator
。
同一算法的std::set::lower_bound
实现能够使用结构的内部细节来避免这个问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.