简体   繁体   English

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

[英]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::advanceForwardIterator

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM