用栈实现队列怎么样?

简介: 用栈实现队列怎么样?

大家好呀,我是蛋蛋。


今天用栈实现队列这道题,是考察对”栈和队列理解程度“的好题。


放心,在实际工作的时候,不是脑残十级,几乎不会提出这样奇怪的需求


话不多说,直接开整。

640.png

   LeetCode 232:用栈实现队列


题意


仅使用两个栈实现先入先出队列,队列支持一般队列支持的所有操作:


void push(int x):将元素 x 推到队列的末尾。


int pop():从队列的开头移除并返回元素。


int peek():返回队列开头的元素。


boolean empty():如果队列为空,返回 true;否则,返回 false。


示例640.png


提示


  • 1 <= x <= 9
  • 最多调用 100 次 push、pop、peek 和 empty
  • 假设所有操作都是有效的(eg. 一个空的队列不会调用 pop 或者 peek 操作)


题目解析


水题,难度简单,主要考察对栈和队列的理解能力


如果对栈和队列还不熟悉,看一下下面这篇文章,某帅比写的:


呔!“栈”住,队列!


仔细来看,主要涉及 4 种常规操作:


  • 入队 push
  • 出队 pop
  • 判空 empty
  • 取队首元素 peek


知道了要求,剩下就是如何用栈模拟队列。


队列是一种先入先出(FIFO)的数据结构,而栈是一种后入先出(LIFO)的数据结构,所以一个栈绝对满足不了队列的 FIFO 的特性。


比如 1 2 3,队列 1 2 3 进,应该 1 2 3 出,但是 1 2 3 进了栈,出来以后会成 3 2 1,和 1 2 3 是相反的,所以再需要一个栈,把 3 2 1 返成 1 2 3。


因此这里需要两个栈,分别是输入栈和输出栈


输入栈来反转元素的入队顺序,元素入只能从输入栈进(push)。


输出栈用来存储元素的正常顺序,元素出只能从输出栈出(pop、peek)。


图解


首先初始化输入栈和输出栈。

640.png


def __init__(self):
    # 初始化输入栈和输出栈
    self.inStack = []
    self.outStack = []


push(x) ,入队操作,直接压入输入栈即可。


比如 push(1)、push(2)。

640.png


def push(self, x: int) -> None:
    # 有新元素进来,进入输入栈
    self.inStack.append(x)


push 操作,每个元素入栈的时间复杂度为 O(1),队列长度为 n,所以时间复杂度为 O(n)。因为需要额外的栈来存储队列中的元素,所以空间复杂度为 O(n)


pop(), 出队操作,如果输出栈不为空的话,直接扔出栈顶元素,输出栈为空的话,那把输入栈的所有元素压入输出栈中,然后再扔出栈顶元素。

640.png

def pop(self) -> int:
    # 如果为空
    if self.empty():
        return None
    # 如果输出栈不为空,返回输出栈中的元素
    if self.outStack:
        return self.outStack.pop()
    # 输出栈为空,将输入栈的元素压入输出栈
    else:
        while self.inStack:
            val = self.inStack.pop()
            self.outStack.append(val)
        return self.outStack.pop()

pop 操作的时间复杂度为 O(n),空间复杂度为 O(n)。


empty(),判空操作。判空很简单,输入栈和输出栈都为空,则队列为空,否则队列不为空。

640.png


def empty(self) -> bool:
      # 两个栈都为空,队列才为空
      if not(self.inStack or self.outStack):
          return True
      return False


队列的首元素使用已有的 pop 函数,时间复杂度和空间复杂度和 pop 一样,时间复杂度和空间复杂度都为 O(n)。


代码实现


Python 代码实现

class MyQueue:
    def __init__(self):
        """
        Initialize your data structure here.
        """
        # 初始化输入栈和输出栈
        self.inStack = []
        self.outStack = []
    def push(self, x: int) -> None:
        """
        Push element x to the back of queue.
        """
        # 有新元素进来,进入输入栈
        self.inStack.append(x)
    def pop(self) -> int:
        """
        Removes the element from in front of queue and returns that element.
        """
        # 如果为空
        if self.empty():
            return None
        # 如果输出栈不为空,返回输出栈中的元素
        if self.outStack:
            return self.outStack.pop()
        # 输出栈为空,将输入栈的元素压入输出栈
        else:
            while self.inStack:
                val = self.inStack.pop()
                self.outStack.append(val)
            return self.outStack.pop()
    def peek(self) -> int:
        """
        Get the front element.
        """
        # 使用已有的函数 pop
        res = self.pop()
        # pop 函数弹出了 res,所以要再添加回去
        self.outStack.append(res)
        return res
    def empty(self) -> bool:
        """
        Returns whether the queue is empty.
        """
        # 两个栈都为空,队列才为空
        if not(self.inStack or self.outStack):
            return True
        return False
# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()


Java 代码实现

class MyQueue {
    Stack<Integer> stack1;
    Stack<Integer> stack2;
    /** Initialize your data structure here. */
    public MyQueue() {
        stack1 = new Stack<>(); // 负责进栈
        stack2 = new Stack<>(); // 负责出栈
    }
    /** Push element x to the back of queue. */
    public void push(int x) {
        stack1.push(x);
    }
    /** Removes the element from in front of queue and returns that element. */
    public int pop() {    
        dumpStack1();
        return stack2.pop();
    }
    /** Get the front element. */
    public int peek() {
        dumpStack1();
        return stack2.peek();
    }
    /** Returns whether the queue is empty. */
    public boolean empty() {
        return stack1.isEmpty() && stack2.isEmpty();
    }
    // 如果stack2为空,那么将stack1中的元素全部放到stack2中
    private void dumpStack1(){
        if (stack2.isEmpty()){
            while (!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
        }
    }
}
/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * boolean param_4 = obj.empty();
 */



图解栈实现队列到这就结束啦,是不是很简单呐,只要熟悉栈和队列就一定会。


如果有问题的话,直接评论区见呀。


动动小手,点赞在看么么哒送上。


我是大帅蛋,我们下次见啦!


640.gif

相关文章
|
1月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
142 77
|
4天前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
1月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
44 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
1月前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
46 9
|
1月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
38 7
|
3月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
99 5
|
3月前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
72 0
|
3月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
332 9
|
3月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
55 1
|
3月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
116 21

热门文章

最新文章