【问题标题】:Which data structure should I use to have fast deletion/insertion and max (or min) search?我应该使用哪种数据结构来进行快速删除/插入和最大(或最小)搜索?
【发布时间】:2013-10-29 16:21:12
【问题描述】:

我正在寻找一种数据结构,它可以确保至少 Log(n) 复杂性以删除和插入节点以及接近 O(1) 或摊销 Log(n) 以搜索最大(或最小值)值.

我正在考虑使用经过修改的自平衡 BST(哪个?)以记住插入的最大值(或最小值)。

有什么建议吗?

抱歉,我必须编辑问题...当然,自平衡 BST 可以允许在 log(n) 中搜索最大值和最小值,但我正在考虑更多关于 O(1) 的内容。

【问题讨论】:

  • 任何平衡的 BST 都允许在 O(lg n) 时间内进行最小和最大查询。一直向左/向右走,直到你碰到一个 nil 孩子。
  • 您可以构建一个“双端”堆,其中最小值和最大值都准备好在O(1) 时间内进行访问。
  • 感谢两位。如果可能的话,我正在寻找比 log(n) 更接近 O(1) 的最大值和最小值,否则我只使用一棵树。关于双端堆,我可以删除 O(lg n) 中的一项吗?
  • 是的,大的 Oh 符号当然隐藏了一些开销,但是双堆支持在 O(lg n) 时间进行插入和删除。
  • @dukeling,这就是我的想法......但我不确定我是否可以在不搜索的情况下跟踪它

标签: algorithm data-structures


【解决方案1】:

您几乎可以使用任何自平衡 BST(例如红黑、AVL)。

如果您跟踪最小值和最大值,获取它们的查询将花费 O(1)。

由于最小值和最大值只能在插入和删除时改变,因此您基本上可以在执行这些操作时重新确定它(在 O(log n) 中)(它们的运行时间仍然是 O(log n))。

尽管当您收到对它的查询并且自上次查询以来存在插入或删除时,重新确定最小值或最大值可能是一个更好的主意。

也有可能对此更加聪明 - 如果您到目前为止只向左走,那么您处于最低限度,如果您只向右走,那么您处于最高水平。插入时,只需在适当的情况下替换最小值/最大值。删除时,只需从已删除节点开始在树中四处寻找新的最小值/最大值。

【讨论】:

  • 好吧,我接受这个答案,因为我记得很多年前我做过类似的事情......我希望有更好的东西:)
【解决方案2】:

AVL 适合:搜索 max 和 min 是 O(log n),因为 min 是最左边的节点,而 max 是最右边的节点,并且树是平衡的。如果您只删除最大/最小节点,这也是 O(log n) 但只有在删除节点会使树不平衡时。

【讨论】:

    【解决方案3】:

    您可以使用red-blacktree 或AVL tree。

    这里找到最小值-最大值,删除一个节点是O(LogN)。

    根据问题的最新编辑,我可以建议您使用可以通过修改的堆栈在 O(1) 中为您提供 O(1) 最小/最大、插入和删除的数据结构。如果有兴趣我可以继续。这完全取决于您的需求、您希望找到最小值/最大值的频率、要插入的位置、删除所有这些特定元素。

    【讨论】:

    • @sebas 是的。如果您遍历正确的孩子,您可以找到最大值。如果您遍历左孩子,则可以找到最小值。
    【解决方案4】:

    我会为此使用skip list。您必须稍作修改才能添加尾指针,但除此之外,它可以满足您的所有需求。修改后:

    • 首先查找是 O(1)
    • 首先删除是 O(1)
    • 查找最后一个是 O(1)
    • 删除最后一个是 O(1)
    • 查找任意节点为 O(log n)
    • 删除任意节点是 O(log n)

    跳过列表并不比二叉堆更难实现,而且我记得,它比实现平衡二叉树要容易得多。我能够从original paper 实现它,它的描述比我见过的大多数学术论文要好得多。

    【讨论】:

      【解决方案5】:

      cmets 已经讨论了双端堆,并得出结论认为它不适合,因为删除需要知道元素的位置。我相信这可以在许多情况下以合理的成本解决,如下所示:维护两个双端堆,一个(比如 A)条目进入集合,一个(比如 B)条目被删除。

      • 要将元素插入集合,请将其插入 A。
      • 要从集合中删除元素,请插入 B。
      • 要获取集合的最大值:如果 B 为空,则返回 A 的最大值。否则,令 mA 为 A 的最大值和 B 的 mB。如果 mA > mB,则 mA 未被删除,您可以把它返还。如果 mA = mB,则它已被删除,您应该从 A 中弹出 mA,从 B 中弹出 mB,然后从该要点的开头开始。你不能有 mA
      • 要获得集合中的最小值,请以明显的方式调整过程以获得最大值。

      这将为您提供 O(log(k)) 插入和删除,以及摊销 O(1) 最小/最大计算。但是,在这种情况下,k 是插入到集合中但尚未从 A 和 B 中弹出的元素数;更明显的其他解决方案具有复杂性,具体取决于集合中实际元素的数量(即,已插入但尚未删除的元素) - 我们称这个数字为 n。您可能会想出 k 远大于 n 以至于这与其他解决方案没有竞争力的场景 - 以及 k 和 n 大致相等且此解决方案更快的其他场景。因此,这是否是一个好主意取决于您的应用程序。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-22
        • 2015-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-20
        • 1970-01-01
        • 2015-11-10
        相关资源
        最近更新 更多