0

0

如何用Python实现栈和队列?

夜晨

夜晨

发布时间:2025-09-05 18:19:02

|

383人浏览过

|

来源于php中文网

原创

使用列表实现栈高效,因append和pop操作均为O(1);但用列表实现队列时,pop(0)为O(n),性能差。应使用collections.deque实现队列,因其popleft为O(1)。封装类可提供更清晰接口和错误处理,适用于复杂场景。频繁出队或大数据量时优选deque,简单栈操作可选list。

如何用python实现栈和队列?

在Python中实现(Stack)和队列(Queue)有几种常见且有效的方法,最直接的方式是利用Python内置的列表(list)或

collections
模块中的
deque
(双端队列)。这两种数据结构本身就具备了实现栈和队列所需的基本操作,只是在性能表现上各有侧重。

解决方案

实现栈(LIFO,后进先出)和队列(FIFO,先进先出)的核心在于控制元素的添加和移除顺序。

1. 使用Python列表实现栈

Python的

list
天生就非常适合作为栈。
append()
方法可以将元素添加到列表的末尾,而
pop()
方法则默认从列表末尾移除元素。这完美符合栈的LIFO特性。

立即学习Python免费学习笔记(深入)”;

# 栈的实现示例
stack = []

# 入栈 (Push)
stack.append('A')
stack.append('B')
stack.append('C')
print(f"入栈后: {stack}") # 输出: ['A', 'B', 'C']

# 出栈 (Pop)
item_c = stack.pop()
print(f"出栈 {item_c} 后: {stack}") # 输出: ['A', 'B']

item_b = stack.pop()
print(f"出栈 {item_b} 后: {stack}") # 输出: ['A']

# 查看栈顶元素 (Peek)
if stack:
    print(f"栈顶元素: {stack[-1]}") # 输出: 'A'

# 检查栈是否为空
print(f"栈是否为空: {not stack}") # 输出: False

2. 使用

collections.deque
实现队列

虽然列表也可以实现队列,但它在从列表头部移除元素时效率较低(

list.pop(0)
是O(n)操作)。这时,
collections.deque
(双端队列)就显得尤为出色了。
deque
支持在两端高效地添加和移除元素,其性能是O(1)。

from collections import deque

# 队列的实现示例
queue = deque()

# 入队 (Enqueue)
queue.append('Task1')
queue.append('Task2')
queue.append('Task3')
print(f"入队后: {queue}") # 输出: deque(['Task1', 'Task2', 'Task3'])

# 出队 (Dequeue)
task1 = queue.popleft() # 从左端移除
print(f"出队 {task1} 后: {queue}") # 输出: deque(['Task2', 'Task3'])

task2 = queue.popleft()
print(f"出队 {task2} 后: {queue}") # 输出: deque(['Task3'])

# 查看队首元素 (Peek)
if queue:
    print(f"队首元素: {queue[0]}") # 输出: 'Task3'

# 检查队列是否为空
print(f"队列是否为空: {not queue}") # 输出: False

Python内置列表作为栈和队列的性能瓶颈是什么?

说实话,用Python的内置

list
来模拟栈,也就是只用
append()
pop()
操作,效率是相当高的,这两种操作的时间复杂度都是O(1)。这意味着无论栈里有多少元素,添加或移除一个元素所需的时间基本是恒定的。所以,对于栈来说,
list
几乎没有性能瓶颈,非常适合。

但当

list
被用作队列时,情况就有点不一样了。队列的特性是先进先出,这意味着我们需要从列表的“头部”移除元素。如果你用
list.pop(0)
来模拟出队操作,那问题就来了。
pop(0)
这个操作,每次都会把列表中所有剩余的元素向前移动一位,以填补被移除元素留下的空位。想象一下,如果你的列表里有几百万个元素,每次出队都要移动几百万个元素,这无疑是个巨大的开销。它的时间复杂度是O(n),n是列表中元素的数量。随着队列的增长,性能会急剧下降,这在处理大量数据或高并发场景下是完全不可接受的。我个人就遇到过一些老项目,为了方便直接用
list.pop(0)
做队列,结果在生产环境跑起来就发现CPU占用居高不下,一查才发现是这里出了问题。所以,对于队列操作,尤其是频繁出队的情况,我强烈建议避免使用
list.pop(0)

GentleAI
GentleAI

GentleAI是一个高效的AI工作平台,为普通人提供智能计算、简单易用的界面和专业技术支持。让人工智能服务每一个人。

下载

除了内置类型,如何用类封装栈和队列,实现更清晰的接口和错误处理?

虽然直接使用

list
deque
很方便,但在更复杂的应用场景中,我们往往希望拥有更清晰、更具表达力的接口,并且能够处理一些边界情况,比如从空栈或空队列中取出元素。这时候,将栈和队列封装成独立的类就显得很有必要了。这样做不仅能提供更语义化的方法名(比如
push
pop
enqueue
dequeue
),还能在内部隐藏实现细节,并加入自定义的错误处理逻辑。

下面是两个简单的类封装示例:

class MyStack:
    def __init__(self):
        # 内部使用列表存储栈元素
        self._items = []

    def push(self, item):
        """元素入栈"""
        self._items.append(item)

    def pop(self):
        """元素出栈,如果栈为空则抛出错误"""
        if not self._items:
            raise IndexError("pop from empty stack")
        return self._items.pop()

    def peek(self):
        """查看栈顶元素,不移除"""
        if not self._items:
            raise IndexError("peek from empty stack")
        return self._items[-1]

    def is_empty(self):
        """判断栈是否为空"""
        return not self._items

    def size(self):
        """返回栈中元素数量"""
        return len(self._items)

    def __str__(self):
        return f"Stack({self._items})"

    def __repr__(self):
        return self.__str__()

# 使用自定义栈
s = MyStack()
s.push(10)
s.push(20)
print(f"我的栈: {s}")
print(f"栈顶元素: {s.peek()}")
print(f"出栈: {s.pop()}")
print(f"栈是否为空: {s.is_empty()}")
print(f"栈大小: {s.size()}")
# s.pop()
# s.pop() # 再次pop会引发IndexError


from collections import deque

class MyQueue:
    def __init__(self):
        # 内部使用collections.deque存储队列元素,保证高效性
        self._items = deque()

    def enqueue(self, item):
        """元素入队"""
        self._items.append(item)

    def dequeue(self):
        """元素出队,如果队列为空则抛出错误"""
        if not self._items:
            raise IndexError("dequeue from empty queue")
        return self._items.popleft()

    def peek(self):
        """查看队首元素,不移除"""
        if not self._items:
            raise IndexError("peek from empty queue")
        return self._items[0]

    def is_empty(self):
        """判断队列是否为空"""
        return not self._items

    def size(self):
        """返回队列中元素数量"""
        return len(self._items)

    def __str__(self):
        return f"Queue({list(self._items)})" # 转换为列表方便打印

    def __repr__(self):
        return self.__str__()

# 使用自定义队列
q = MyQueue()
q.enqueue('JobA')
q.enqueue('JobB')
print(f"我的队列: {q}")
print(f"队首元素: {q.peek()}")
print(f"出队: {q.dequeue()}")
print(f"队列是否为空: {q.is_empty()}")
print(f"队列大小: {q.size()}")
# q.dequeue()
# q.dequeue() # 再次dequeue会引发IndexError

通过类封装,我们不仅拥有了更直观的API,还可以在方法内部加入各种逻辑,比如在

pop()
dequeue()
之前检查是否为空,从而避免运行时错误,或者记录操作日志,甚至可以扩展成线程安全的版本。这让代码更健壮,也更易于维护和理解。

什么时候应该选择
collections.deque
而不是普通列表来模拟栈和队列?

这是一个很实际的问题,选择哪种数据结构确实需要根据具体场景来定。在我看来,

collections.deque
和普通列表各有其最佳使用场景,没有绝对的优劣,关键在于“合适”。

选择

collections.deque
的场景:

  1. 作为队列使用时,特别是需要频繁从头部移除元素: 这是
    deque
    最主要的优势。正如前面提到的,
    list.pop(0)
    的O(n)性能在处理大量数据时会成为瓶颈,而
    deque.popleft()
    是O(1)。如果你在实现广度优先搜索(BFS)、任务调度器、日志处理队列等需要频繁“出队”的场景,那么
    deque
    几乎是唯一的选择。
  2. 作为双端队列使用时: 如果你的需求不仅是栈或队列,而是需要在两端都进行高效的添加和移除操作,比如实现一个历史记录功能,既能添加新记录,又能回溯旧记录,
    deque
    append()
    ,
    appendleft()
    ,
    pop()
    ,
    popleft()
    都能提供O(1)的性能。
  3. 对性能有严格要求,且数据量可能很大: 当你的程序需要处理大量数据,并且对响应时间有较高要求时,
    deque
    的恒定时间复杂度优势就非常明显了。它避免了列表在中间或头部操作时可能出现的元素复制和移动开销。
  4. 需要固定大小的循环缓冲区:
    deque
    有一个
    maxlen
    参数,可以创建一个固定大小的双端队列。当队列满时,再添加新元素会自动从另一端移除最老的元素。这对于实现滑动窗口、最近访问列表等功能非常方便,省去了手动管理大小的麻烦。

选择普通列表(

list
)的场景:

  1. 作为栈使用时: 如果你仅仅是需要一个栈,只在列表的末尾进行
    append()
    pop()
    操作,那么普通列表完全够用,而且其实现也更简洁直观。在这种情况下,
    list
    deque
    的性能差异可以忽略不计。
  2. 数据量较小,且对性能要求不那么极致: 对于小规模数据,即使偶尔有
    list.pop(0)
    这样的O(n)操作,其影响也可能微乎其微。代码的简洁性和可读性有时比极致性能更重要。
  3. 需要频繁随机访问元素: 列表支持通过索引进行O(1)的随机访问(
    my_list[index]
    ),而
    deque
    虽然也支持索引访问,但在内部实现上,它的随机访问效率不如列表。如果你除了栈/队列操作外,还需要频繁地根据索引访问中间元素,那么列表可能更合适。

总的来说,当涉及到队列操作,尤其是需要从头部移除元素时,

collections.deque
是Pythonic且高效的选择。而如果只是简单的栈操作,或者数据量不大且需要随机访问,那么列表的简洁性也很有吸引力。理解它们底层的工作原理和时间复杂度,能帮助我们做出更明智的技术决策。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

550

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

30

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

45

2026.01.06

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1958

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

658

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2401

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

47

2026.01.19

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

447

2023.07.18

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1万人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号