【问题标题】:Deque in which all pushes/pops (front/back) and get_min() are O(1) operations所有推送/弹出(前/后)和 get_min() 都是 O(1) 操作的双端队列
【发布时间】:2020-12-25 04:48:52
【问题描述】:

我只是想知道,对于get_min(), push_back(), push_front(), pop_back(), pop_front() 操作,是否有可能实现具有O(1) 复杂度(const/amortized 无关紧要) 的结构(列表/双端队列)?

绝对有可能实现stack 甚至queue(对他们来说push()pop() 只能用于一端)满足这些条件。但我无法将此逻辑重用于出队案例。

还可以创建具有O(logn) 复杂性的结构,用于推送/弹出和O(1) 用于get_min(只需使用简单列表和min_heap,其中可以删除O(logn) 的任意元素) .

但对我来说,所有操作仍然摊销O(1) 似乎是不可能的。如果是这种情况,关于操作的确切数量(或列表中可能的最大元素数量)n 的信息是否有帮助(更简单的情况)?我们能以某种方式使用O(n)(甚至更多)额外的内存或像这样的东西吗?

【问题讨论】:

    标签: c++ algorithm data-structures min priority-queue


    【解决方案1】:

    确实可以构建一个最小双端队列,其中前推、后推和查找最小操作在最坏情况时间 O(1) 中工作,并且前弹出和后弹出操作摊销时间 O(1)。我知道的最简单的路线是这样的:

    1. 首先,创建a stack that supports push, pop, and find-min in time O(1)。我们将使用它作为构建块。
    2. 使用从三个堆栈构建双端队列的结构,除了使用这些最小堆栈而不是常规堆栈。然后,您可以通过查询三个堆栈中每个堆栈的最小元素并返回这些值的最小值来实现 find-min 操作。

    如果您还没有看到如何执行第 (2) 步,这个想法是对 how to make a queue from two stacks 的概括。您维护两个代表双端队列元素的堆栈,一个堆栈以相反的顺序代表双端队列的前端(堆栈顶部是双端队列的前端,更深的元素是双端队列的下一个元素)和另一个的元素stack 代表双端队列的后面(顶部元素是双端队列的最后一个元素,更深的元素通过双端队列向后)。例如,这是对双端队列 1、2、3、...、10 进行编码的一种方法:

    front: | 7 6 5 4 3 2 1
    back:  | 8 9 10
    

    要推入双端队列的前面或后面,只需推入相应的双端队列即可。要弹出双端队列的前部或后部,如果适当的堆栈非空,只需从中弹出即可。否则,如果堆栈为空,则需要将一些元素从另一个堆栈移过来。具体来说,为了保持两个堆栈之间的平衡,您执行一系列推送和弹出操作以将一半元素放入两个堆栈中的每一个中。看起来像这样:

    1. 从另一个堆栈中弹出一半元素并将它们压入临时堆栈。
    2. 从另一个堆栈中弹出剩余的元素并将它们压入空堆栈。
    3. 从临时堆栈中弹出元素并将它们推回另一个堆栈。

    您可以使用潜在参数(参见 Φ 是两个堆栈的高度差的绝对值)表明每个操作需要分摊时间 O(1)。

    有可能使用某种调度方案以某种方式将每次操作的最坏情况 O(1) 时间加快,但我不确定如何做到这一点。我知道有一种方法可以实现一个有四个堆栈的队列,每个操作的最坏情况 O(1),所以也许这个想法可以推广到这里工作?

    【讨论】:

    • @ALX23x 您的编辑没有使用标准术语,并且 OP 已经指定摊销复杂性适用于他们,因此编辑也是多余的。
    • 认为你是对的:这是如何将 queue 逻辑重新应用于双端队列的实际方法(我自己无法弄清楚)。只需要几分钟来更仔细地考虑一下(以防止错误接受),然后将您的答案标记为正确。谢谢!
    • @KonradRudolf 在回答中指定它是哪种 O(1) 很重要。堆栈实现最大为 O(1)。我也不熟悉导致它被忽略的“摊销”。 “最大”和“平均”相当常见且易于理解。
    • @ALX23z “平均”和“摊销”之间有一个重要区别,这使得这两个术语不可互换。 “平均”对于被平均的内容是模棱两可的,并且可能暗示随机性。 “摊销”意味着“这些操作的任何序列都保证不会超过这个时间量,除以执行的操作数量。”有关摊销的更多信息,请参阅these lecture slides
    • @templatetypedef 我很确定你可以通过Kaplan and Tarjan 来装饰实时功能双端队列,并使用子树最小值,但也许我错过了一些微妙的细节。
    猜你喜欢
    • 1970-01-01
    • 2017-04-04
    • 2018-01-22
    • 2018-09-08
    • 2021-02-24
    • 1970-01-01
    • 2011-01-18
    相关资源
    最近更新 更多