1571 字
8 分钟
python算法学习之列队与双端列队
一、队列的基本概念
队列(Queue) 是一种先进先出(FIFO - First In First Out) 的线性数据结构。 队列的核心操作:
- 入队(Enqueue):添加元素到队尾
- 出队(Dequeue):移除队首元素
- 查看队首(Front/Peek):查看但不移除队首元素
- 判断空(isEmpty):检查队列是否为空
- 获取大小(Size):获取队列中元素数量
队列就像排队买票:
- 新来的人排在队尾(入队)
- 买完票的人从队首离开(出队)
- 先来的人先服务(先进先出)
二、列队的两种视角
-
数组实现(顺序队列) 前端(front) ← [元素1, 元素2, 元素3] ← 后端(rear) 出队← ←入队
-
链表实现(链式队列) front → 节点1 → 节点2 → 节点3 → rear
三、队列的实现方式
-
基于数组的实现(顺序队列)
class ArrayQueue:"""基于数组的循环队列实现"""def __init__(self, capacity=10):self.capacity = capacityself.queue = [None] * capacityself.front = 0 # 队首指针self.rear = 0 # 队尾指针(指向下一个空位置)self.size = 0 # 当前元素数量def __str__(self):if self.is_empty():return "Queue: []"elements = []for i in range(self.size):idx = (self.front + i) % self.capacityelements.append(str(self.queue[idx]))return f"Queue: [{', '.join(elements)}] (front:{self.front}, rear:{self.rear})"def is_empty(self):return self.size == 0def is_full(self):return self.size == self.capacitydef enqueue(self, value):"""入队 - O(1)"""if self.is_full():self._resize()self.queue[self.rear] = valueself.rear = (self.rear + 1) % self.capacity # 循环self.size += 1def dequeue(self):"""出队 - O(1)"""if self.is_empty():raise IndexError("Dequeue from empty queue")value = self.queue[self.front]self.queue[self.front] = None # 可选:帮助垃圾回收self.front = (self.front + 1) % self.capacity # 循环self.size -= 1return valuedef peek(self):"""查看队首元素 - O(1)"""if self.is_empty():raise IndexError("Peek from empty queue")return self.queue[self.front]def get_size(self):return self.sizedef _resize(self):"""动态扩容 - O(n)"""self.capacity *= 2new_queue = [None] * self.capacity# 复制元素到新数组,保持顺序for i in range(self.size):old_idx = (self.front + i) % (self.capacity // 2)new_queue[i] = self.queue[old_idx]self.queue = new_queueself.front = 0self.rear = self.size测试循环队列
queue = ArrayQueue(3)queue.enqueue(1)queue.enqueue(2)queue.enqueue(3)print(queue) # Queue: [1, 2, 3]print("队首:", queue.peek()) # 1print("出队:", queue.dequeue()) # 1queue.enqueue(4)print(queue) # Queue: [2, 3, 4] -
基于链表的实现(链式队列)
class Node:"""链表节点"""def __init__(self, value):self.value = valueself.next = Noneclass LinkedListQueue:"""基于链表的队列实现"""def __init__(self):self.front = None # 队首节点self.rear = None # 队尾节点self._size = 0def __str__(self):values = []current = self.frontwhile current:values.append(str(current.value))current = current.nextreturn " → ".join(values) + " → None" if values else "Empty Queue"def is_empty(self):return self.front is Nonedef enqueue(self, value):"""入队 - O(1)"""new_node = Node(value)if self.is_empty():self.front = self.rear = new_nodeelse:self.rear.next = new_nodeself.rear = new_nodeself._size += 1def dequeue(self):"""出队 - O(1)"""if self.is_empty():raise IndexError("Dequeue from empty queue")value = self.front.valueself.front = self.front.next# 如果队列变空,更新rearif self.front is None:self.rear = Noneself._size -= 1return valuedef peek(self):"""查看队首 - O(1)"""if self.is_empty():raise IndexError("Peek from empty queue")return self.front.valuedef size(self):return self._size测试链表队列
ll_queue = LinkedListQueue()ll_queue.enqueue(1)ll_queue.enqueue(2)ll_queue.enqueue(3)print("链表队列:", ll_queue) # 1 → 2 → 3 → Noneprint("队首:", ll_queue.peek()) # 1print("出队:", ll_queue.dequeue()) # 1print("链表队列:", ll_queue) # 2 → 3 → None
四、双端队列(Deque)
双端队列(Deque - Double Ended Queue) 是一种允许从两端进行插入和删除操作的数据结构。 双端队列的核心操作:
- 前端操作:add_front / remove_front / peek_front
- 后端操作:add_rear / remove_rear / peek_rear
- 可以同时当作栈和队列使用
双端队列就像双向通道:
- 可以从两端进入
- 可以从两端离开
- 更灵活的数据结构
五、双端队列的实现
class ArrayDeque: """基于数组的双端队列实现(循环数组)""" def __init__(self, capacity=10): self.capacity = capacity self.deque = [None] * capacity self.front = 0 # 指向队首元素 self.rear = 0 # 指向队尾的下一个位置 self.size = 0
def __str__(self): if self.is_empty(): return "Deque: []"
elements = [] for i in range(self.size): idx = (self.front + i) % self.capacity elements.append(str(self.deque[idx])) return f"Deque: [{', '.join(elements)}]"
def is_empty(self): return self.size == 0
def is_full(self): return self.size == self.capacity
def _resize(self): """动态扩容""" self.capacity *= 2 new_deque = [None] * self.capacity
for i in range(self.size): old_idx = (self.front + i) % (self.capacity // 2) new_deque[i] = self.deque[old_idx]
self.deque = new_deque self.front = 0 self.rear = self.size
def add_front(self, value): """前端添加 - O(1)""" if self.is_full(): self._resize()
self.front = (self.front - 1) % self.capacity self.deque[self.front] = value self.size += 1
def add_rear(self, value): """后端添加 - O(1)""" if self.is_full(): self._resize()
self.deque[self.rear] = value self.rear = (self.rear + 1) % self.capacity self.size += 1
def remove_front(self): """前端移除 - O(1)""" if self.is_empty(): raise IndexError("Remove from empty deque")
value = self.deque[self.front] self.deque[self.front] = None self.front = (self.front + 1) % self.capacity self.size -= 1 return value
def remove_rear(self): """后端移除 - O(1)""" if self.is_empty(): raise IndexError("Remove from empty deque")
self.rear = (self.rear - 1) % self.capacity value = self.deque[self.rear] self.deque[self.rear] = None self.size -= 1 return value
def peek_front(self): """查看前端 - O(1)""" if self.is_empty(): raise IndexError("Peek from empty deque") return self.deque[self.front]
def peek_rear(self): """查看后端 - O(1)""" if self.is_empty(): raise IndexError("Peek from empty deque") return self.deque[(self.rear - 1) % self.capacity]
def size(self): return self.size测试双端队列
deque = ArrayDeque(5)deque.add_rear(1) # 后端添加deque.add_rear(2)deque.add_front(0) # 前端添加deque.add_rear(3)print(deque) # Deque: [0, 1, 2, 3]print("前端:", deque.peek_front()) # 0print("后端:", deque.peek_rear()) # 3print("移除前端:", deque.remove_front()) # 0print("移除后端:", deque.remove_rear()) # 3print(deque) # Deque: [1, 2]六、对比

七、队列的经典应用场景(打印队列管理)
class PrinterQueue: """打印机队列模拟""" def __init__(self): self.queue = deque() self.current_job = None
def add_print_job(self, document, pages, priority="normal"): """添加打印任务""" job = { 'document': document, 'pages': pages, 'priority': priority, 'status': 'waiting' }
# 根据优先级插入 if priority == "high": # 插入到普通任务前面 temp_queue = deque() inserted = False while self.queue: job_in_queue = self.queue.popleft() if not inserted and job_in_queue['priority'] == "normal": temp_queue.append(job) inserted = True temp_queue.append(job_in_queue)
if not inserted: temp_queue.append(job)
self.queue = temp_queue else: self.queue.append(job)
print(f"添加打印任务: {document} ({pages}页)")
def process_next_job(self): """处理下一个任务""" if not self.queue: print("没有待处理的任务") return None
self.current_job = self.queue.popleft() self.current_job['status'] = 'printing' print(f"正在打印: {self.current_job['document']}") return self.current_job
def cancel_job(self, document): """取消指定任务""" for job in list(self.queue): if job['document'] == document: self.queue.remove(job) print(f"已取消任务: {document}") return True print(f"未找到任务: {document}") return False
def show_queue(self): """显示当前队列""" print("\n当前打印队列:") for i, job in enumerate(self.queue, 1): print(f"{i}. {job['document']} ({job['pages']}页) - {job['priority']}优先级")总之
队列思维:先进先出,公平排队 适用场景:需要按顺序处理、先来后到
关键点:
- 队尾入,队首出
- 保持顺序不变
- 常用于缓冲、调度
双端队列思维:两头都能操作,灵活多变 适用场景:需要从两端操作、滑动窗口、同时需要栈和队列功能
关键点:
- 两端都可以插入删除
- 可以模拟栈和队列
- 常用于维护单调性
这里有点难,应该在LeetCode上多练习.
python算法学习之列队与双端列队
https://tclothes.online/posts/算法3/sf3/ 部分信息可能已经过时









