栈与队列: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
总结
栈和队列虽然简单,但它们是构建复杂算法和系统的基础。理解它们的特性和适用场景,能够帮助我们在面对具体问题时选择最合适的数据结构。无论是函数调用、任务调度还是算法实现,栈和队列都发挥着不可替代的作用。
"简单的东西往往最强大,栈和队列就是最好的证明。"
















