std :: set begin()和std :: set迭代器之间的距离为O(logn)

时间:2012-09-21 11:56:00

标签: c++ stl iterator set std

我需要在std :: set中找到元素的索引。此索引可以显示为迭代器从头开始的距离。 一种方法可以是:

for(int i = 0, set<int>::iterator it = s.begin(); it != iteratorToBeFound; ++it, ++i);

这显然需要O(n)时间。但我们知道,在内部使用set实现的二叉搜索树中根的距离可以在O(log n)时间内找到。

他们以任何方式实现相同的方法来在C ++集中的O(log n)时间内找到索引吗?

5 个答案:

答案 0 :(得分:4)

您可以使用函数std::set<>::find搜索元素x并计算distance到集合的第一个迭代器。

std::distance(s.begin(), s.find(x))

但是,正如注释所示,距离的运行时间取决于所使用的迭代器的类型。在set的情况下,这是一个双向迭代器,距离是O(n)。

答案 1 :(得分:3)

您可以使用已排序的std::vector<int>。如果已排序,您可以在O(log n)中找到元素。你可以在恒定时间内找到距离O(1)

按照排序的向量,我的意思是每次插入后(或多次插入后),你都会std::sort(v.begin(), v.end());

如果std::set<T>中的类型不像int那么轻 - 你可以保留 - std::set<T>和迭代器std::vector<std::set<T>::iterator>的有序向量。但保持这些结构同步并不容易。也许你可以在T添加一些类似的位置?或者保持std::set<std::pair<T,int>, comp_first_of_pair<T>> comp_first_of_pair只需要set仅按T排序,第二int用于保持位置设置?

只是一些想法 - 甚至有O(1)距离时间......

答案 2 :(得分:1)

您不能将物联网用于双向迭代器。因此,唯一可接受的方法是自己计算(少于 int 少于插入集合中的X)。

但是,如果你已经将“数据收集”和“数据使用”阶段分开了 - 可能值得将 std :: set 替换为已排序的 std :: vector 。它更难维护,但有自己的好处,包括迭代器材料(因此你可以使用 std :: binary_search 进行O(log n)搜索,并与O(1)进行距离

答案 3 :(得分:1)

如果计算索引真的你的瓶颈,那么我会看到2个选项:

  • 存储索引。无论是在节点本身还是在单独的std::map中。 当然,这意味着您必须更新此缓存。
  • 使用std::vector。这并不像最初看起来那么糟糕。 如果您始终对矢量进行排序,则可以像set一样使用它。 性能与set类似。 最大的缺点是:节点可能被复制很多。 (这可以通过使用指针boost:shared_ptrstd::unique_ptr [仅限c ++ 11]来补偿)
    要查找使用std::lower_bound的元素。
    您可以执行:insert( lower_bound(b,e,x), x )
  • 而不是插入/推送

答案 4 :(得分:1)

您可以在O(log(N))中的一个有序集合https://www.geeksforgeeks.org/ordered-set-gnu-c-pbds/中找到一个元素的索引。这被实现为一棵红黑树。我知道这个主题很老,但是将来可能会对读者有所帮助。