CC++ & Algorithm

Python队列(deque实现)

中等2
语言版本:C++Python
概述:队列就像排队买冰淇淋,先进先出,Python的`deque`能高效实现。

排队打饭不插队:Python 队列(deque 实现)

你有没有在食堂排过队?先来的人先打到饭,后来的人乖乖站在后面,这就是“先进先出”的规则。在编程里,这种结构就叫队列(Queue)。Python 的 deque(读作“德克”)是一种双端队列,能高效实现普通队列的操作,是 GESP 考试和日常编程的好帮手。

什么是队列?先来先服务

队列像一条等待的队伍:

  • 入队(enqueue):新元素从队尾加入,就像新同学站到队伍最后。
  • 出队(dequeue):总是从队首离开,比如队伍最前面的同学先买到冰淇淋。

队列严格遵循 FIFO(First In, First Out) 原则——先进去的先出来。这和栈(后进先出)正好相反。

生活中的队列

场景怎么排队
食堂打饭第一个排队的同学先打到饭
打印店先提交的文档先打印
游乐园过山车先排队的人先上车
老师批改作业先交上去的本子先批改

就连你玩的游戏里,消息队列也按顺序处理聊天信息,不会让后来的消息插队。

Python 里怎么实现队列?用 deque

Python 的列表(list)也能模拟队列,比如用 append() 在尾部添加、pop(0) 在头部删除。但 pop(0) 太慢了——因为列表删除第一个元素后,所有后面的元素都要往前挪动一位,像教室里第一排同学走了,后面整排都要往前移,非常费时间。

deque 来自 collections 模块,专门为两端操作优化,无论从左边还是右边添加或删除,速度都极快。请看基本操作:

from collections import deque  # 导入双端队列

# 创建一个空队列,用来模拟食堂打饭的队伍
queue = deque()

# 入队:同学们依次来排队
queue.append("小明")   # 小明先来,站到队尾
queue.append("小红")   # 小红后来,站到小明后面
queue.append("小刚")   # 小刚最后,站到最后
print("当前队列:", queue)  # 输出:deque(['小明', '小红', '小刚'])

# 出队:队伍最前面的小明先离开(打饭走了)
first = queue.popleft()
print("出队的是:", first)   # 输出:小明
print("剩余队列:", queue)   # 输出:deque(['小红', '小刚'])

# 只看队首是谁,但不让他离开
print("队首是:", queue[0])  # 输出:小红

为什么选 deque 而不是列表?

操作列表deque
尾部添加 append()
头部删除 pop(0)(所有元素左移)极快
头部添加 appendleft()极快
尾部删除 pop()

简单说:如果只从后面进、前面出(标准队列),deque 的效率比列表高得多。尤其是队伍有几千人时,列表会卡顿,而 deque 依然飞快。

队列的常用操作(记住这五个)

from collections import deque

q = deque()                # 空队列
q.append("apple")           # 入队(尾部添加)
q.append("banana")
q.append("cherry")

first = q.popleft()         # 出队(头部取出),first 变成 "apple"
head = q[0]                 # 查看队首,不取出,此时 head 是 "banana"

is_empty = len(q) == 0      # 判断队列是否为空,False
queue_len = len(q)          # 获取队列长度,现在是 2(banana, cherry)

新手容易犯的错误

错误1:忘记导入 deque

# 错误:
queue = deque()  # NameError: name 'deque' is not defined
# 改正:先写 from collections import deque

错误2:用列表的 pop(0) 代替 popleft()

# 错误(虽然能运行但很慢):
queue = [1, 2, 3]
first = queue.pop(0)  # 列表弹出第一个元素
# 正确做法:用 deque
from collections import deque
q = deque([1, 2, 3])
first = q.popleft()

错误3:对空队列执行 popleft()

q = deque()
q.popleft()  # 报错:IndexError: pop from an empty deque
# 改正:先判断是否为空
if q:
    q.popleft()

错误4:以为 deque 只能当队列

deque 是双端队列,不仅可以当队列(左出右进),还能当栈(右进右出)。用 pop()append() 就像栈一样工作。

完整示例:模拟打印店排队

小明、小红、小刚、小华去打印店。先来的先打印,每人打印需要固定时间。我们用队列模拟打印顺序。

from collections import deque

# 创建打印任务队列,按到达顺序加入
print_queue = deque()

# 模拟同学们陆续来提交打印任务
print_queue.append("小明作业.pdf")   # 小明先到
print_queue.append("小红海报.jpg")   # 小明正在打印时,小红来了
print_queue.append("小刚简历.doc")   # 小红排队中,小刚来了
print_queue.append("小华试卷.pdf")   # 小刚排队中,小华来了

print("初始打印队列:", list(print_queue))

# 打印机开始工作,按顺序打印
print("\n=== 打印机开始工作 ===")
while print_queue:  # 只要队列还有人
    job = print_queue.popleft()          # 取出最前面的任务
    print(f"正在打印:{job}")
    # 假设打印需要 1 秒(用 input 模拟暂停)
    input("按回车键继续下一个...")

print("\n所有打印任务完成!")

运行这个程序,你会看到任务按“先进先出”顺序被处理。

相关指引

队列在编程中非常常用,尤其在以下场景:

  • 广度优先搜索(BFS):走迷宫、找最短路径时,用队列保存待探索的节点。
  • 任务调度:操作系统按顺序执行任务。
  • 消息队列:聊天软件按顺序发送消息。

如果你对队列的对头——(后进先出)感兴趣,可以看看《Python栈(列表实现)》。如果想了解更灵活的双端操作,学习《deque 双端队列进阶用法》。掌握队列后,你就能解决很多实际排队问题啦!

例题精讲

1单选题

下面哪个方法可以将元素添加到Python deque(双端队列)的左侧?

Aappend()
Bappendleft()
Cpush()
Dinsert()
2判断题

Python的deque(双端队列)遵循先进先出(FIFO)原则,因此只能从一端添加元素,从另一端移除元素。

3填空题
以下代码使用deque实现了一个简单的队列,请补全缺失的部分。\nfrom collections import deque\nq = deque()\nq.____('A')\nq.____('B')\nfirst = q.____()\nprint(first)  # 应输出A
4单选题

若使用deque来实现队列,以下哪个操作的时间复杂度最差?

Aappend()
Bpopleft()
Cappendleft()
Dindex()
5判断题

使用deque实现队列时,若要从队列中取出元素,应使用pop()方法而不是popleft()。