为啥我们要“使用 2 个堆栈实现一个队列”? [复制]

Posted

技术标签:

【中文标题】为啥我们要“使用 2 个堆栈实现一个队列”? [复制]【英文标题】:Why do we do "implement a queue using 2 stacks"? [duplicate]为什么我们要“使用 2 个堆栈实现一个队列”? [复制] 【发布时间】:2011-11-15 18:15:48 【问题描述】:

可能重复:Why use two stacks to make a queue?

我收到了这个作业问题,要求我使用两个堆栈实现一个队列。我的问题不是怎么做,而是为什么要做?我不是计算机背景,我试图找到答案,但真的找不到为什么要这样做?我认为你们的专家可以帮助我了解实施这样的事情有什么好处。我找到了一篇相关的文章Why use two stacks to make a queue? 谈论这个,但想知道是否还有更多内容。

【问题讨论】:

我认为它没有任何优势。他们只是想看看您是否足够了解这两种数据结构,是否可以做到。好吧,也许有些语言有内置的堆栈数据类型,但没有队列。 @Tom:真的很快。这真的很有帮助。非常感谢。 @Oli:我经历了它,但无法从中得到真正的答案。于是我又问了一遍。感谢您的帮助。 @smandape:如果您无法理解另一个问题的答案,那么您真正的问题可能是关于纯函数数据结构的目的? 不幸的是,得到答案并不会减少问题,所以我正在投票结束。 【参考方案1】:

这样做有几个很好的理由。

首先,一些函数式编程语言(如 Haskell、ML 或 Lisp)支持将列表作为内置类型。列表通常表示为单个的前向链接列表,这意味着它们支持 O(1) 前置但 O(n) 连接。在像这样的语言中,创建堆栈非常容易 - 您只需在列表前面添加和删除第一个要弹出的元素。由于内部实现,这在 O(1) 时间内运行。如果您尝试使用这种列表创建队列,则入队将花费 O(n) 时间,因为您必须添加到不存储指向最后一个元素的指针的单链表的末尾。另一方面,如果您使用两个堆栈(或更多;Hood-Melville queue 使用六个!)来实现队列,那么即使您的语言中只有堆栈,您也可以获得分摊的 O(1) 入队和出队。尽管已经设计出更高级的数据结构来支持纯函数式队列和列表(例如2-3 finger tree),但两栈结构在许多应用程序中仍然非常有用。

除此之外,在某些情况下,您可能希望使用特殊的堆栈来实现队列以获取额外的功能。例如,您可以augment a stack data structure 来支持 O(1) find-min/find-max。如果你有这样的堆栈,那么你可以use the two-stack construction to make a queue that also has O(1) find-min/find-max。尝试直接解决这个问题要困难得多(查看我的considerably more complex construction 以使用这些属性创建队列!)

最后,从理论的角度来看,一个队列可以用两个堆栈来模拟是很有趣的。在可计算性理论中,two-stack pushdown automaton 是一种理论计算设备,其功能相当于图灵机。 queue automaton 是一个类似的结构,它使用一个队列而不是两个堆栈。因为我们知道你可以模拟一个有两个堆栈的队列,所以你可以立即证明队列自动机至少和图灵机一样强大,因此队列自动机是图灵完备的。

希望这会有所帮助!

【讨论】:

这真的很有帮助,让像我这样的非计算机人清楚地理解事物。感谢您的帮助,感谢您提供的答案链接。 只是出于兴趣,你有没有引用断言将队列实现为两个堆栈是摊销 O(1)? @paxdiablo- 这里有一个很棒的资源 (cs.cmu.edu/afs/cs.cmu.edu/academic/class/15750-s04/www/…),它是由扩展堆的发明者 Daniel Sleator 提供的。希望这会有所帮助! @hattenn 它不一定是不可变的(你也可以用这种方式制作可变队列),但它是实现不可变队列的好方法。采用这种方法很容易,并且不会让 push 和 pop 操作更改队列,而是返回一个新队列。所以你现在有一个旧队列不变,一个新队列。一个有趣的特性是,由于这些队列是不可变的,并且内部堆栈也可以是不可变的,那么这些具有不同堆栈的不同队列将包含许多共同的子堆栈(因为它们是不可变的)可以安全地是相同的堆栈,内存使用率低。 @templatetypedef:我认为您的队列自动机参数的方向是错误的:假设我有一台图灵机,您必须构建一个模仿它的队列自动机。你把我的图灵机变成一个两栈自动机,然后……什么?将您的队列自动机转换为两栈式自动机?但是哪个队列自动机?您需要展示您声称的是基于队列的两个堆栈的仿真;你可以用你的假设表明队列自动机并不更多比图灵完备。

以上是关于为啥我们要“使用 2 个堆栈实现一个队列”? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

希望开复老师早日康复

Spring工程 使用复选选按钮

为啥我们要使用 sqlcommandbuilder?

为啥powedesigner 安装完成后表里面字段不能设置 identity 没有 那么identity 选项框..

如何在收藏视图中显示复选标记(图像)

为啥我们要合并几个select语句