【问题标题】:What is the right data structure for a queue that support Min, Max operations in O(1) time?在 O(1) 时间内支持 Min、Max 操作的队列的正确数据结构是什么?
【发布时间】:2015-06-22 20:56:16
【问题描述】:

对于支持 Enque、Dequeue、Peak、Min 和 Max 操作并在 O(1) 时间内执行所有这些操作的队列来说,正确的数据结构是什么。

最明显的数据结构是链表,但 Min, Max 操作是 O(n)。 Priority Queue 是另一个完美的选择,但 Enqueue、Dequeue 应该以队列的正常方式工作。 (先进先出)

想到的另一个选项是堆,但我不太清楚如何使用堆设计具有最小、最大操作的队列。

非常感谢任何帮助。

【问题讨论】:

  • 我不确定是否存在这样的数据结构。您可能想混合使用队列和特里树(或某种平衡树),但有些操作需要 O(log(n))
  • 另外,programmers 可能是一个更好的提问地点。
  • 可以设计一个满足所有这些要求的堆栈。通过存储最多每个元素的 Min 和 Max 值,我们可以在 O(1) 时间内找到 Min 和 Max,但使用队列会更棘手。我认为应该有办法,因为我知道有人已经实现了这一点。但我不知道怎么做。
  • 不,如果你弹出 Min 或 Max 值,你的 Stack 不是 O(1)
  • 问题并不完全清楚:是否 min() 和 max() 从结构中删除元素,或者它们是只读的?如果是只读的,那么 O(1) stack-with-min-max 肯定是可能的(但是,不是队列)。如果不是只读的,那么@BasileStarynkevitch 是正确的,这样的结构将无法按预期工作。

标签: queue heap


【解决方案1】:

如果 min() 和 max() 实际改变了结构,则无法设计您寻求的数据结构。如果 min() 和 max() 与 peek() 类似,并且提供只读访问权限,那么您应该按照this question 中的步骤,添加另一个类似于用于 min() 操作的 deque 以用于 max () 手术。该答案的其余部分假定 min() 和 max() 实际上 删除 相应的元素。

由于您需要 enqueue() 和 dequeue(),因此必须按到达顺序 (FIFO) 添加和删除元素。一个简单的双端队列(链接或使用循环向量)将在 O(1) 中提供这一点。

但是要添加的元素可能会改变当前的 min() 和 max();但是,当删除时,应该恢复旧的 min() 和 max() 值......除非它们在过渡期间被删除。此限制迫使您以某种方式保持元素排序。任何排序结构(最小堆、最大堆、平衡二叉树……)都需要至少 O(log n) 才能找到新到达的位置

最好的办法是将平衡二叉树(用于 min() 和 max())与双向链表配对。您的树节点将存储一组指向列表节点的指针,按您在 min() 和 max() 中使用的任何键进行排序。在 Java 中:

// N your node class; can return K, comparable, used for min() and max() 
LinkedList<N> list;           // sorted by arrival
TreeMap<K,HashMap<N>> tree;   // sorted by K
  • enque() 上,您将在list 的末尾添加一个新节点,并通过其键将同一节点添加到HashMap 中其节点@987654325 中的@987654325 @。 O(log n).
  • dequeue() 上,您将从list 的开头删除节点,并从其树中节点的HashMap 中删除。 O(log n).
  • min() 上,您将查找树中的第一个元素。 O(1)。如果你需要删除它,你有指向链表的指针,所以那一侧是 O(1);但是如果它是具有特定 K 的最后一个元素,则 O(log n) 重新平衡树。
  • ma​​x() 上,同样的逻辑适用;除了您将寻找树中的最后一个元素。所以 O(log n).
  • peek() 上,查看但不提取队列中的第一个元素将是 O(1)

如果您知道所有键都是唯一的,则可以简化此操作(通过删除 HashMap)。但是,这不会影响渐近成本:它们都将保持不变。

实际上,O(log n)O(1) 之间的差异是如此之小,以至于 C++ 的 STL 中的默认映射实现是 O( log n)-基于(树而不是哈希)。

【讨论】:

    【解决方案2】:

    假设

    您只关心性能而不关心空间/内存/ ...

    解决方案

    索引是一个集合,而不是一个列表(适用于列表,但可能需要一些额外的爱)

    你可以同时做一个队列和一个哈希表。

    示例

    假设顺序是 5 4 7 1 8 3

    队列 -> 547813

    哈希表 -> 134578

    入队

    1) 取出您的对象,并插入到正确存储桶中的哈希表中 Min / Max 将始终是第一个和最后一个索引。 (参见排序哈希表)

    2) 接下来,像往常一样插入队列。

    3) 您可以/应该将两者联系起来。一种想法是使用哈希表值作为指向队列的指针。

    两个大哈希表的操作都是 O(1)

    出队

    1) 弹出第一个元素 O(1)

    2) 从哈希表中移除元素 O(1)

    最小值/最大值

    1) 查看您的哈希表。根据所使用的语言,理论上您可以通过查看表格的头部或表格的尾部来找到它。

    为了更好地解释排序哈希表,https://stackoverflow.com/questions/2007212

    注意: 我想指出,没有“正常”的数据结构可以满足我所知道的您的要求。但是,这并不意味着不可能。如果您要尝试实现数据结构,很可能您将不得不根据自己的需要进行操作,并且无法使用当前可用的库。您可能不得不考虑使用像汇编这样的非常低级的语言来实现这一点,但如果您擅长这些语言,也许 C 或 Java 可能能够做到。

    祝你好运

    已编辑: 我没有解释排序的哈希表,所以添加了另一个 SO 的链接来解释它们。

    【讨论】:

    • 您正在混淆哈希表(无顺序保证)和树映射(有顺序保证,但 O(log n) 而不是 O(1))。哈希表的“头”和“尾”与最小值/最大值无关
    • 取决于您使用的哈希表。如果您使用插入在值上的 1 对 1 哈希表,则不会。例如,如果我的数字范围是 1 到 10,而我的映射是 1 到 10,我可以让值在表中的行上插入。由于大多数数组插入不是 O(1),所以我没有那样做。您的假设是哈希键与值无关,这是正常的,但并非总是如此。插入值 10 时,插入第 10 行,值 2 时插入第 2 行。我将编辑答案以更好地解释该部分。
    • 更新帖子指向已排序的哈希表。没有“标准”的方法可以做到这一点,所以 OP 必须根据 OP 的情况来弄清楚。
    • 对不起,Jdhaern,但链接的问题并没有解释“排序的哈希表”——它只是请求它们。这样的生物不存在。它接受的答案指向一个 TreeMap (不以任何方式散列,并且所有操作的 O(log n) )。您的答案仍然将 HashMaps 的低成本与 TreeMaps 的顺序保持特性混合在一起;它仍然是一个错误的答案
    • 您阅读答案了吗?我没有“解释”它们,但给你找了一个。它非常棘手,因为它涉及许多指针。而且我确实了解您来自 Java 背景,请考虑较低级别。此外,它不是“正常”哈希图。您将不得不涉及某种其他数据结构来提供帮助。你也应该看看 TreeMaps。因为它们与我所描述的并不接近。您有 100 行,并且您将对象的值插入到行中。那不是 TreeMap。
    【解决方案3】:

    这个结构不存在!

    有一个简单的方法可以验证这个结论。

    众所周知,排序问题的复杂度是O(nlogn)。 但是如果你说的结构存在,那么排序会有一个解决方案:

    1. 逐个查询每个元素的成本 O(n)
    2. 将每个最大(或最小)元素逐一出列花费 O(n)

    表示排序问题可以通过O(n)解决。但它不可能

    【讨论】:

    • 很好的证明——任何实现修改 min() 或 max() 的结构都意味着排序方面的重大突破。另一方面,尚不清楚 OP 是否意味着“只读” min() 和 max()。
    • 证明的良好开端,但没有完全清除。您的假设似乎是我们没有排序列表。双向链表单独删除了反驳 #2。这也似乎假设该结构不能具有有关其在队列中的位置的元信息。我承认用算法证明不是非常困难。也许更多的迭代,这可以得到证明。但这远非不可能。
    • 我认为这是“证明这种结构将是排序方面的巨大突破”,而不是“证明这种结构是不可能的”。在第一种意义上,它是铁定的:如果你可以在 O(n) 中插入并在 O(n) 中删除Min,那么你可以在 O(n) 中排序(!!)。在第二种意义上,证明小于 O(n log n) 的排序是“不可能的”比进行@lessmoon 的观察要困难得多。然而,许多非常聪明的人已经尝试改进 O(n log n),并且可以肯定它无法改进。也适用于基于二进制比较交换的算法。
    • 嗯,最后一行“这意味着排序问题可以通过 O(n) 解决。但这是不可能的。”接缝“证明这种结构是不可能的”。我猜它的解释。祝你以后有证据好运。
    【解决方案4】:

    任何可以在 O(1) 时间内检索到 MinMax 的数据结构都需要在每个 InsertRemove 上花费至少 O(log n) 来维护部分排序的元素。实现这一点的数据结构称为优先队列

    基本优先级队列支持InsertMaxRemoveMax。有很多方法可以构建它们,但 binary heaps work best.

    使用单个优先级队列支持所有InsertMinRemoveMinMaxRemoveMax 更加复杂。论文中描述了一种使用从二进制堆改编的单一数据结构的方法:

    阿特金森、迈克尔 D. 等人。 “Min-max heaps and generalized priority queues.”ACM 通信 29.10 (1986):996-1000。

    它快速且节省内存,但需要非常小心才能正确实施。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-06-12
      • 1970-01-01
      • 1970-01-01
      • 2011-01-27
      • 2018-05-23
      • 2013-10-03
      • 2013-11-16
      相关资源
      最近更新 更多