使用 2 个堆栈实现队列,具有恒定的时间复杂度

Posted

技术标签:

【中文标题】使用 2 个堆栈实现队列,具有恒定的时间复杂度【英文标题】:implement queue using 2 stacks, with constant time complexity 【发布时间】:2021-12-24 03:15:46 【问题描述】:

我想知道是否可以使用两个堆栈来实现一个队列,这样每个队列操作都需要摊销的常数时间。

【问题讨论】:

【参考方案1】:
class QQ: 
    def __init__(self): 
        self.s = [] 
        self.ss = [] 
    def enque(self, val): 
        self.s.append(val) 
    def deque(self): 
        if not self.s and not self.ss: return None 
        if not self.ss: 
            while self.s: 
                self.ss.append(self.s.pop()) 
        return self.ss.pop() 

当我们将s 的元素弹出到ss 中时,第二个堆栈ss 以相反的顺序保存第一个堆栈s 的内容。反向堆栈只是一个队列。每当ss 为空时,我们将s 中的所有元素加载到ss 中。如果它不为空,我们只需 deque 从中提取一个元素。

时间复杂度是摊销常数,因为我们只对enqueing 进行了一次移动,而从长远来看,dequeing 只进行了两次移动。

【讨论】:

谢谢,但是这里deque()的复杂度不是O(1) 如果将 while 循环更改为 0:self.s.length,那么,由于我们知道重复次数,复杂度将为 O(1) 乘以等于 O(1) 的常数。但无论如何,我要感谢你帮助我。 deque 具有摊销的O(1) 时间复杂度。也许你不熟悉python。 while self.s,其中s 是一个列表,执行您使用0:self.s.length 描述的内容。当self.s 拥有任何成员时,这是真的。当它为空时,它会破裂。【参考方案2】:

我们使用 2 个带有标签“前”和“后”的堆栈。

在栈前我们应该使用size和clear方法,size返回栈的指针,clear设置指针为0。

对于enqueue(),我们应该将新元素推送到前端堆栈。所以时间复杂度将是O(1)

对于dequeue(),如果后栈为空,我们应该用前栈中的元素填充它,对于前栈中的每个元素,我们应该调用pop()函数,然后使用push()函数将其插入后栈,因为我们知道前栈的大小(并且它是恒定的)并且pop和push函数的时间复杂度为O(1),所以出队的整体复杂度将是O(1)

对于size(),它将返回前堆栈和后堆栈的总和size()。 对于isEmpty(),它应该返回大小是否等于零。

【讨论】:

以上是关于使用 2 个堆栈实现队列,具有恒定的时间复杂度的主要内容,如果未能解决你的问题,请参考以下文章

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

使用两个队列实现堆栈

iOS,音频队列:缓冲区大小不是恒定的

std :: deque(双端队列)真的是随机访问和恒定时间插入吗?

在恒定时间内找到堆栈中的最小元素

在动态队列中维护后端的目的是什么?