栈与队列:后进先出与先进先出的智慧

数据结构里的两种秩序,一个像叠盘子,一个像排队。

👋 你好,我是 Evan,一名计算机专业的学长,也是《大一突围》专栏的作者。学完数组和链表后,下一个该学什么?栈和队列------它们是"受限"的线性表,但正因为限制,它们解决了无数实际问题:函数调用、括号匹配、浏览器回退、任务调度......今天我用最直观的方式,带你彻底搞懂栈和队列的 push/pop 与 enqueue/dequeue。

欢迎来到 《大一突围》 专栏。

一、栈(Stack):后进先出(LIFO)

1.1 形象比喻

一叠盘子:你只能从顶部取(pop),也只在顶部放(push)。最后放上去的盘子,最先被拿走。

1.2 核心操作

  • push(item):将元素压入栈顶

  • pop():移除并返回栈顶元素

  • peek() / top():查看栈顶元素但不移除

  • isEmpty():判断栈是否为空

1.3 栈的图示

1.4 代码实现(Python + Java)

🐍 Python 示例(使用 list)
python 复制代码
class Stack:
    def __init__(self):
        self.items = []
    def push(self, item):
        self.items.append(item)
    def pop(self):
        if not self.is_empty():
            return self.items.pop()
    def peek(self):
        if not self.is_empty():
            return self.items[-1]
    def is_empty(self):
        return len(self.items) == 0

# 使用
s = Stack()
s.push(1); s.push(2); s.push(3)
print(s.pop())   # 3
print(s.peek())  # 2
☕ Java 示例(使用 Deque)
java 复制代码
import java.util.ArrayDeque;
import java.util.Deque;

public class StackDemo {
    public static void main(String[] args) {
        Deque<Integer> stack = new ArrayDeque<>();
        stack.push(1);   // 等价于 addFirst
        stack.push(2);
        stack.push(3);
        System.out.println(stack.pop());   // 3
        System.out.println(stack.peek());  // 2
    }
}

1.5 经典应用场景

  • 函数调用栈:调用方法时压栈,返回时出栈。

  • 括号匹配{ ( [ ) ] } 用栈检查是否配对。

  • 撤销操作(Undo):每次操作压栈,撤销时出栈。

  • 浏览器后退:访问新页面压栈,后退弹出。

二、队列(Queue):先进先出(FIFO)

2.1 形象比喻

排队买票:先来的先买到,后来的排在队尾。队头出队(dequeue),队尾入队(enqueue)。

2.2 核心操作

  • enqueue(item):将元素加入队尾

  • dequeue():移除并返回队头元素

  • front() / peek():查看队头元素

  • isEmpty():判断队列是否为空

2.3 队列的图示

2.4 代码实现(Python + Java)

🐍 Python 示例(使用 collections.deque)
python 复制代码
from collections import deque

class Queue:
    def __init__(self):
        self.items = deque()
    def enqueue(self, item):
        self.items.append(item)   # 队尾入
    def dequeue(self):
        if not self.is_empty():
            return self.items.popleft()  # 队头出
    def front(self):
        if not self.is_empty():
            return self.items[0]
    def is_empty(self):
        return len(self.items) == 0

# 使用
q = Queue()
q.enqueue(1); q.enqueue(2); q.enqueue(3)
print(q.dequeue())   # 1
print(q.front())     # 2
☕ Java 示例(使用 Queue 接口)
java 复制代码
import java.util.LinkedList;
import java.util.Queue;

public class QueueDemo {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(1);   // enqueue
        queue.offer(2);
        queue.offer(3);
        System.out.println(queue.poll());   // dequeue → 1
        System.out.println(queue.peek());   // 查看队头 → 2
    }
}

2.5 经典应用场景

  • 任务调度(打印队列、进程调度)。

  • 广度优先搜索(BFS):借助队列逐层遍历图。

  • 消息队列(如 RabbitMQ、Kafka 的底层概念)。

  • 键盘缓冲区:你敲的字符先进入队列,系统依次处理。

三、栈 vs 队列:对比总结

代码操作对比表

四、进阶:用数组实现一个循环队列

常规队列用数组实现时,队头出队后前面的空间浪费。循环队列可以重用空间。

循环队列示意图

Python 实现(固定大小)

python 复制代码
class CircularQueue:
    def __init__(self, capacity):
        self.capacity = capacity
        self.queue = [None] * capacity
        self.front = 0
        self.rear = 0
        self.size = 0

    def enqueue(self, item):
        if self.size == self.capacity:
            raise Exception("Queue is full")
        self.queue[self.rear] = item
        self.rear = (self.rear + 1) % self.capacity
        self.size += 1

    def dequeue(self):
        if self.size == 0:
            raise Exception("Queue is empty")
        item = self.queue[self.front]
        self.front = (self.front + 1) % self.capacity
        self.size -= 1
        return item

这个实现不仅更节省空间,而且广泛应用于操作系统和底层库。

五、实战练习:用栈实现队列

这是一道经典的面试题:仅使用两个栈实现队列的 enqueue 和 dequeue 操作

思路:一个栈作为输入栈(用于 enqueue),另一个栈作为输出栈(用于 dequeue)。当需要 dequeue 时,如果输出栈为空,就把输入栈的所有元素弹出并压入输出栈。

python 复制代码
class QueueUsingTwoStacks:
    def __init__(self):
        self.in_stack = []
        self.out_stack = []

    def enqueue(self, item):
        self.in_stack.append(item)

    def dequeue(self):
        if not self.out_stack:
            while self.in_stack:
                self.out_stack.append(self.in_stack.pop())
        if not self.out_stack:
            raise Exception("Queue is empty")
        return self.out_stack.pop()

# 测试
q = QueueUsingTwoStacks()
q.enqueue(1); q.enqueue(2); q.enqueue(3)
print(q.dequeue())  # 1
print(q.dequeue())  # 2
q.enqueue(4)
print(q.dequeue())  # 3
print(q.dequeue())  # 4

六、Evan 的一句话总结

  • :优先照顾"后来者",适合需要回溯、逆向的场景。

  • 队列:公平对待"先来者",适合需要顺序、缓存的场景。

掌握这两种数据结构,你就掌握了一半的算法基础。

❓ 问题:你有没有遇到过用栈或队列巧妙地解决某个实际问题的例子?或者你还分不清什么时候用栈、什么时候用队列?欢迎在评论区分享你的理解或困惑,我会选出 3 位同学,送出《栈和队列经典面试题集合》PDF。

📌 如果本文帮你理清了栈与队列的区别,请点 👍 赞 + 关注 ,本专栏 《大一突围》 持续输出数据结构与算法干货。

收藏本文,下次面试前回看,不再混淆 push/pop 和 enqueue/dequeue。

相关推荐
曲幽4 小时前
刚部署的 LibreTranslate 频频翻车?我掏出了 20 年前的 StarDict 词典,用 FastAPI 搭了个本地词典翻译 API
python·fastapi·web·translate·goldendict·libretranslate·stardict·pystardict
荣码5 小时前
用Streamlit给AI应用套个界面,10行代码出Web页面
java·python
兵慌码乱14 小时前
基于Python+PyQt5+SQLite的药房管理系统实现:事务一致性与界面解耦全流程解析
python·sqlite·信号与槽·pyqt5·数据库设计·桌面应用开发·事务处理
金銀銅鐵16 小时前
[Python] 体验用欧几里得算法计算最大公约数的过程
python·数学
FreakStudio20 小时前
W55MH32L-EVB 上手测评:硬件 TCP/IP 加持的以太网单片机,MicroPython 零门槛开发
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机
用户03321266636721 小时前
使用 Python 从零创建 Word 文档
python
Csvn1 天前
Python 两大经典坑点 —— 可变默认参数 & 闭包延迟绑定
后端·python
曲幽1 天前
别再用网页翻译看源码了!你的私人翻译神器LibreTranslate,部署避坑指南来了
python·docker·web·pot·translate·libretranslate·arogstranslate
用户556918817531 天前
#从脚本到独立程序:Python + Playwright 批量抓取的完整踩坑记录
python·自动化运维
兵慌码乱2 天前
基于 MediaPipe 与 PySide2 的手势交互音乐控制系统实现:轻量化视觉交互全流程解析
python·opencv·计算机视觉·人机交互·手势识别·mediapipe·pyside2