【问题标题】:What container allows both binary_search'ing and random deletion of elements?什么容器允许二进制搜索和随机删除元素?
【发布时间】:2014-12-09 08:31:27
【问题描述】:

我一直在使用std::vector,但随着它迭代的数据的增长,它变得笨拙,我希望能够在随机元素变得多余时过滤掉它们。我在 std::list 的其他地方也有这种行为,但无法让 binary_search 与之相处融洽。

是否有一些代码可以让binary_search 再次工作,或者我必须使用更复杂的容器和语法?

        if(binary_search(iter + 1, myLines.end(), line)) {
            firstFound.assign(line);
            if (numFinds++) break;
        }

【问题讨论】:

标签: c++ list map stl containers


【解决方案1】:

std::set 的查找是 O(log(N)),与 binary_search 完全相同,如果有迭代器,则删除是 O(1),如果没有迭代器,则为 O(log(N))(查找 + 删除)。尽管该集合将存储已排序的元素,但这对您来说一定没问题,因为binary_search 也仅适用于已排序的范围。

【讨论】:

  • 是的,我已经对数据进行了排序,它也是独一无二的,如果这很重要的话,虽然我忘记了那个细节。谢谢,似乎比地图更直观。
  • @John:如果你需要非唯一的数据,multiset
  • 注:你不能使用 std::binary_search()std::set 迭代器,因为它们不是 RandomAccessIterators,但你可以使用 std::set::find() 和其他成员,例如 std::set::count()std::set::lower_bound(),它们是作为容器的二进制搜索实现的。跨度>
  • 我放弃了大部分新容器并重新使用std::vector,而不是删除元素(使用set时我没有权利iterator这样做)我将无效的条目放入set,以便在以后的迭代中很容易忽略它们。很高兴学习另一个标准容器,比maps 好得多。两年前,我一直在用mallocfree 模拟我自己的班级。
【解决方案2】:

听起来您正在寻找的是binary search tree (BST)

它允许二进制搜索(毕竟它在名称中),删除相对简单。

存在多种二叉搜索树。一些常见的:

  • simple BST :最坏情况和最佳情况搜索性能之间的差距很大,具体取决于 BST 的具体用法(插入和删除)。树越高,性能越差。
  • self-balancing BST :在每次插入/删除时,如果需要,节点会四处移动,以保持树的高度最小,从而优化搜索性能。这是以插入和删除时增加的开销(可能会变得高得令人望而却步)为代价的。
  • red-black tree :一种自平衡的 BST,并不总是争取最佳高度,但仍然足以保持查找 O(log n)。它在广泛的用例中表现非常一致(即具有良好的通用性能),这就是为什么选择它来实现std::set(参见Armen Tsirunyan's answer)。
  • splay tree :BST 将最近访问的项目保存在树的顶部,在那里可以最快地访问它们。它不是自平衡的,因此高度不会保持最小。当最近访问的数据可能很快会再次被访问时,这种树非常有用。
  • treap:使用随机优先级的 BST 分配给项目,以便可能(即使用概率论)保持树的高度接近最小。它不能保证最佳的搜索性能,但在实践中通常可以,而且不会增加自平衡或类似重组算法的开销。

其中哪一个最适合您,取决于您的具体用例。

【讨论】:

  • 我没有投反对票,但我想原因是 BST 已经很好地包装在 std::map 和 std::set 中,因此无需重新发明轮子。
  • 不管怎样,这是一个 +1 补偿
  • 澄清为什么我认为值得添加这个答案:红黑树确实是一种自平衡二叉搜索树,因此使用std::set 是一种选择(根据@ArmenTsirunyan 的回答)。但是它比普通的 BST 有更多的开销(主要是由于重新平衡),这可能是不可取的。你也不需要自己动手——现有的实现很容易获得(尽管不是标准库的一部分)。
  • 您评论中的错误是正常 BST 中的查找不是 O(LogN),而是 O(H),其中 H 是树的高度。在最坏的情况下,H 可以是 N,使得查找线性化!
  • @ArmenTsirunyan :这是真的,但如果我对 OP 描述的理解(一些“随机”删除,没有提及添加)是正确的,那么最坏情况的风险非常小。我同意你的观点,std::set 可能是更好的主意(如果只是因为它是最简单的),但如果用例允许,并且性能是一个问题,一个简单的 BST 是一个替代方案。我可能应该扩展我的答案以使所有这些更清楚。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-22
  • 2016-06-15
  • 1970-01-01
相关资源
最近更新 更多