栈与队列:LIFO与FIFO的完美演绎

摘要

栈(Stack)和队列(Queue)是两种基础但极其重要的线性数据结构,分别遵循后进先出(LIFO)和先进先出(FIFO)原则。本文将深入探讨它们的实现原理、操作特性、应用场景以及在实际开发中的巧妙运用。

1. 栈(Stack):后进先出的艺术

1.1 基本概念与操作

栈是一种限制插入和删除只能在一端进行的线性表。

# 栈的基本操作示例
stack = []
stack.append(1)  # 压栈 push
stack.append(2)
stack.append(3)
top = stack[-1]  # 查看栈顶 peek
popped = stack.pop()  # 出栈 pop → 3
核心操作:
  • push:向栈顶添加元素
  • pop:从栈顶移除元素
  • peek/top:查看栈顶元素不移除
  • isEmpty:检查栈是否为空

1.2 实现方式对比

数组实现:
class ArrayStack:
    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()
        raise Exception("Stack is empty")
    
    def peek(self):
        if not self.is_empty():
            return self.items[-1]
        raise Exception("Stack is empty")
    
    def is_empty(self):
        return len(self.items) == 0
    
    def size(self):
        return len(self.items)
链表实现:
class LinkedStack:
    class Node:
        def __init__(self, data):
            self.data = data
            self.next = None
    
    def __init__(self):
        self.top = None
        self.size = 0
    
    def push(self, data):
        new_node = self.Node(data)
        new_node.next = self.top
        self.top = new_node
        self.size += 1
    
    def pop(self):
        if self.is_empty():
            raise Exception("Stack is empty")
        data = self.top.data
        self.top = self.top.next
        self.size -= 1
        return data
    
    def peek(self):
        if self.is_empty():
            raise Exception("Stack is empty")
        return self.top.data
    
    def is_empty(self):
        return self.top is None

1.3 栈的应用场景

括号匹配检查:
def is_valid_parentheses(s: str) -> bool:
    stack = []
    mapping = {')': '(', '}': '{', ']': '['}
    
    for char in s:
        if char in mapping.values():
            stack.append(char)
        elif char in mapping:
            if not stack or stack.pop() != mapping[char]:
                return False
    return not stack
函数调用栈:
# 递归函数的栈模拟
def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n-1)

# 调用栈示例:factorial(3)
# 栈状态: [factorial(3)] → [factorial(2)] → [factorial(1)] → [factorial(0)]

2. 队列(Queue):先进先出的秩序

2.1 基本概念与操作

队列是一种限制插入在一端进行,删除在另一端进行的线性表。

from collections import deque

queue = deque()
queue.append(1)  # 入队 enqueue
queue.append(2)
queue.append(3)
front = queue[0]  # 查看队首
dequeued = queue.popleft()  # 出队 dequeue → 1
核心操作:
  • enqueue:向队尾添加元素
  • dequeue:从队首移除元素
  • front:查看队首元素
  • isEmpty:检查队列是否为空

2.2 队列变种与应用

循环队列:
class CircularQueue:
    def __init__(self, k: int):
        self.queue = [None] * k
        self.head = 0
        self.tail = 0
        self.size = 0
        self.capacity = k
    
    def enqueue(self, value: int) -> bool:
        if self.is_full():
            return False
        self.queue[self.tail] = value
        self.tail = (self.tail + 1) % self.capacity
        self.size += 1
        return True
    
    def dequeue(self) -> bool:
        if self.is_empty():
            return False
        self.head = (self.head + 1) % self.capacity
        self.size -= 1
        return True
    
    def front(self) -> int:
        if self.is_empty():
            return -1
        return self.queue[self.head]
    
    def is_empty(self) -> bool:
        return self.size == 0
    
    def is_full(self) -> bool:
        return self.size == self.capacity
优先队列:
import heapq

class PriorityQueue:
    def __init__(self):
        self.heap = []
    
    def push(self, item, priority):
        heapq.heappush(self.heap, (priority, item))
    
    def pop(self):
        return heapq.heappop(self.heap)[1]
    
    def is_empty(self):
        return len(self.heap) == 0

3. 栈与队列性能对比

特性 栈(Stack) 队列(Queue)
原则 LIFO(后进先出) FIFO(先进先出)
插入位置 栈顶 队尾
删除位置 栈顶 队首
时间复杂度 O(1)所有操作 O(1)所有操作
典型应用 函数调用、括号匹配 任务调度、消息队列

4. 实战应用案例

4.1 栈的应用

  • 浏览器历史记录:前进后退功能
  • 文本编辑器撤销:操作历史栈
  • 表达式求值:中缀转后缀表达式
  • 深度优先搜索:递归或显式栈实现

4.2 队列的应用

  • 消息队列:RabbitMQ、Kafka等
  • 线程池任务调度:任务等待队列
  • 广度优先搜索:层次遍历
  • 打印机任务管理:先来先服务
# BFS使用队列实现
def bfs(graph, start):
    visited = set()
    queue = deque([start])
    visited.add(start)
    
    while queue:
        node = queue.popleft()
        print(node, end=" ")
        
        for neighbor in graph[node]:
            if neighbor not in visited:
                visited.add(neighbor)
                queue.append(neighbor)

5. 高级话题:双端队列(Deque)

双端队列结合了栈和队列的特性,支持两端的高效操作。

from collections import deque

d = deque()
d.appendleft(1)  # 前端添加
d.append(2)      # 后端添加
d.popleft()      # 前端移除 → 1
d.pop()          # 后端移除 → 2

总结

栈和队列虽然简单,但它们是构建复杂算法和系统的基础。理解它们的特性和适用场景,能够帮助我们在面对具体问题时选择最合适的数据结构。无论是函数调用、任务调度还是算法实现,栈和队列都发挥着不可替代的作用。

"简单的东西往往最强大,栈和队列就是最好的证明。"