[英]C++ Difference between std::lower_bound and std::set::lower_bound?
Recently, while working on a programming problem in C++, I came across something interesting.最近,在处理 C++ 编程问题时,我遇到了一些有趣的事情。 My algorithm used a really large set and would use std::lower_bound on it a great deal of times.
我的算法使用了一个非常大的集合,并且会多次使用 std::lower_bound 。 However, after submitting my solution, contrary to the math I did on paper to prove that my code was fast enough, it ended up being far too slow.
然而,在提交我的解决方案后,与我在纸上做的数学证明我的代码足够快相反,它最终太慢了。 The code looked something like this:
代码如下所示:
using namespace std;
set<int> s;
int x;
//code code code
set<int>::iterator it = lower_bound(s.begin(),s.end(),x);
However, after getting a hint from a buddy to use set::lower_bound, the algorithm in question worked waaaaaaaay faster than before, and it followed my math.但是,在从朋友那里得到使用 set::lower_bound 的提示后,所讨论的算法的运行速度比以前快了 waaaaaaaay,并且按照我的数学计算。 The binary search after changing:
更改后的二分查找:
set<int>::iterator it = s.lower_bound(x);
My question is what's the difference between these two?我的问题是这两者有什么区别? Why does one work much, much faster than the other?
为什么一个工作得比另一个快得多? Isn't lower_bound supposed to be a binary search function that has the complexity O(log2(n))?
难道lower_bound 不应该是一个复杂度为O(log2(n)) 的二分查找函数吗? In my code it ended up being way slower than that.
在我的代码中,它最终比这慢得多。
std::set
is typically implemented as a self-balancing tree with some list like structure tied into it. std::set
通常被实现为一个自平衡树,其中包含一些类似列表的结构。 Knowing this structure, std::set::lower_bound
will traverse the tree knowing the properties of the tree structure.知道这个结构,
std::set::lower_bound
将遍历树,知道树结构的属性。 Each step in this just means following a left or right child branch.这其中的每一步都意味着遵循左子分支或右子分支。
std::lower_bound
needs to run something akin to a binary search over the data. std::lower_bound
需要对数据运行类似于二进制搜索的东西。 However since std::set::iterator
is bidirectional, this is much slower, a lot of increments need to be done between the checked elements.但是,由于
std::set::iterator
是双向的,因此速度要慢得多,需要在检查元素之间进行大量增量。 The work done between elements is thus much more intense.因此,元素之间所做的工作更加激烈。 In this case the algorithm will check the element half way between A and B, then adjust one of A or B, find the element half way between them, and repeat.
在这种情况下,算法将检查 A 和 B 中间的元素,然后调整 A 或 B 之一,找到它们中间的元素,然后重复。
After reading the API of std::lower_bound阅读std::lower_bound的 API 后
On non-random-access iterators, the iterator advances produce themselves an additional linear complexity in N on average.
在非随机访问迭代器上,迭代器前进平均会产生 N 中的额外线性复杂度。
And I think STL set is using non-random-access iterators, so it is not doing a O(log N) binary search if using on STL set而且我认为 STL 集使用的是非随机访问迭代器,因此如果在 STL 集上使用,它不会进行 O(log N) 二进制搜索
std::lower_bound
is a generic binary search algorithm, meant to work with most STL containers. std::lower_bound
是一种通用的二分搜索算法,适用于大多数 STL 容器。 set::lower_bound
is designed to work with std::set
so it takes advantages of the unique properties of std::set
. set::lower_bound
旨在与std::set
因此它利用了std::set
的独特属性。
As std::set
is often implemented as a red-black tree, one can imagine std::lower_bound
iterating across all nodes, while set::lower_bound
just traverses down the tree.由于
std::set
通常被实现为一棵红黑树,因此可以想象std::lower_bound
遍历所有节点,而set::lower_bound
只是向下遍历树。
std::lower_bound
always guarantees a O(log n)
comparisons , only guarantees O(log n)
time if passed a RandomAccessIterator
, not just a ForwardIterator
which does not provide constant-time std::advance
. std::lower_bound
始终保证O(log n)
比较,如果传递RandomAccessIterator
,则仅保证O(log n)
时间,而不仅仅是不提供恒定时间std::advance
的ForwardIterator
。
The std::set::lower_bound
implementation of the same algorithm is able to use internal details of the structure to avoid this problem.同一算法的
std::set::lower_bound
实现能够使用结构的内部细节来避免这个问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.