展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > Python中的几种栈实现及其优缺点

Python中的几种栈实现及其优缺点

​​想了解更多关于开源的内容,请访问:​​​​51CTO开源基础软件社区​​​​https://ost.51cto.com​​一、栈的概念栈由一系列对象对象组织的一个集合,这些对象的增加和删除操作都遵循一个“后进先出”(LastInFirstOut,LIFO)的原则。在任何时刻只能向栈中插入一个对象,但只能取得或者删除只能在栈顶进行。比如由书构成的栈,唯一露出封面的书就是顶部的那本,为了拿到其他的书,只能移除压在上面的书,如图:栈的实际应用实际上很多应用程序都会用到栈,比如:网络浏览器将最近浏览的

本文目录

    Python中的几种栈实现及其优缺点

    ​​想了解更多关于开源的内容,请访问:​​

    ​​51CTO 开源基础软件社区​​

    ​​https://ost.51cto.com​​

    一、栈的概念

    栈由一系列对象对象组织的一个集合,这些对象的增加和删除操作都遵循一个“后进先出”(Last In First Out,LIFO)的原则。

    在任何时刻只能向栈中插入一个对象,但只能取得或者删除只能在栈顶进行。比如由书构成的栈,唯一露出封面的书就是顶部的那本,为了拿到其他的书,只能移除压在上面的书,如图:

    Python中的几种栈实现及其优缺点

    栈的实际应用

    实际上很多应用程序都会用到栈,比如:

    1. 网络浏览器将最近浏览的网址存放在一个栈中。每当用户访问者访问一个新网站时,这个新网站的网址就被压入栈顶。这样,每当我们在浏览器单击“后退”按钮时(或者按键盘快捷键 CTRL+Z ,大部分撤销快捷键),就可以弹出当前最近一次访问的网址,以回到其先前访问的浏览状态。
    2. 文本编辑器通常会提供一个“撤销”机制以取消最近的编辑操作并返回到先前状态。这个撤销操作也是通过将文本的变化状态保存在一个栈中得以实现。
    3. 一些高级语言的内存管理,JVM 的栈、Python 栈还用于内存管理、嵌套语言特性的运行时环境等
    4. 回溯(玩游戏,寻找路径,穷举搜索)
    5. 在算法中使用,如汉诺塔、树形遍历、直方图问题,也用于图算法,如拓扑排序
    6. 语法处理:
    • 参数和局部变量的空间是用堆栈在内部创建的。
    • 编译器对大括号匹配的语法检查
    • 对递归的支持
    • 在编译器中像后缀或前缀一样的表达式

    二、栈的抽象数据类型

    任何数据结构都离不开数据的保存和获得方式,如前所述,栈是元素的有序集合,添加和操作与移除都发生在其顶端(栈顶),那么它的抽象数据类型包括:

    • Stack() :创建一个空栈,它不需要参数,且会返回一个空栈。
    • push(e): 将一个元素 e 添加到栈 S 的栈顶,它需要一个参数 e,且无返回值。
    • pop() : 将栈顶端的元素移除,它不需要参数,但会返回顶端的元素,并且修改栈的内容。
    • top(): 返回栈顶端的元素,但是并不移除栈顶元素;若栈为空,这个操作会操作。
    • is_empty(): 如果栈中不包含任何元素,则返回一个布尔值True。
    • size():返回栈中元素的数据。它不需要参数,且会返回一个整数。在 Python 中,可以用__len__ 这个特殊方法实现。

    Python中的几种栈实现及其优缺点

    Python 栈的大小可能是固定的,也可能有一个动态的实现,即允许大小变化。在大小固定栈的情况下,试图向已经满的栈添加一个元素会导致栈溢出异常。同样,试图从一个已经是空的栈中移除一个元素,进行 ​​pop()​​ 操作这种情况被称为下溢。

    三、用 Python 的列表实现栈

    在学习 Python 的时候,一定学过 Python 列表 ​​list​​ , 它能通过一些内置的方式实现栈的功能:

    • 通过append 方法用于添加一个元素到列表尾部,这种方式就能模拟push() 操作。
    • 通过pop() 方法用于模拟出栈操作。
    • 通过L[-1] 模拟top()操作。
    • 通过判断len(L)==0 模拟isEmpty() 操作。
    • 通过len() 函数实现size() 函数。

    Python中的几种栈实现及其优缺点

    代码如下:

    class ArrayStack:
    """ 通过 Python 列表实现 LIFO 栈"""
    def __init__(self):
    self._data = []
    def size(self):
    """ return the number of elements in the stack"""
    return len(self._data)
    def is_empty(self):
    """ return True if the stack is empty"""
    return len(self._data) == 0
    def push(self, e):
    """ add element e to the top of the stack"""
    self._data.append(e)
    
    def pop(self):
    """ remove and return the element from the top of the stack
    """
    if self.is_empty():
    raise Exception('Stack is empty')
    return self._data.pop()
    def top(self):
    """return the top of the stack
    Raise Empty exception if the stack is empty
    """
    if self.is_empty():
    raise Exception('Stack is empty')
    return self._data[-1]# the last item in the list
    arrayStack = ArrayStack()
    arrayStack.push("Python")
    arrayStack.push("Learning")
    arrayStack.push("Hello")
    print("Stack top element: ", arrayStack.top())
    print("Stack length: ", arrayStack.size())
    print("Stack popped item: %s" % arrayStack.pop())
    print("Stack is empty?", arrayStack.is_empty())
    arrayStack.pop()
    arrayStack.pop()
    print("Stack is empty?", arrayStack.is_empty())
    # arrayStack.pop()

    运行该程序,结果:

    Stack top element:Hello
    Stack length:3
    Stack popped item: Hello
    Stack is empty? False
    Stack is empty? True

    除了将列表的队尾作为栈顶,也可以通过将列表的头部作为栈的顶端。不过在这种情况下,便无法直接使用 pop() 方法和 append()方法,但是可以通过 pop() 和 insert() 方法显式地访问下标为 0 的元素,即列表的第一个元素,代码如下:

    class ArrayStack:
    """ 通过 Python 列表实现 LIFO 栈"""
    def __init__(self):
    self._data = []
    def size(self):
    """ return the number of elements in the stack"""
    return len(self._data)
    def is_empty(self):
    """ return True if the stack is empty"""
    return len(self._data) == 0
    def push(self, e):
    """ add element e to the top of the stack"""
    self._data.insert(0, e) 
    def pop(self):
    """ remove and return the element from the top of the stack
    """
    if self.is_empty():
    raise Exception('Stack is empty')
    return self._data.pop(0)
    def top(self):
    """return the top of the stack
    Raise Empty exception if the stack is empty
    """
    if self.is_empty():
    raise Exception('Stack is empty')
    return self._data[0]# the last item in the list

    虽然我们改变了抽象数据类型的实现,却保留了其逻辑特征,这种能力体现了抽象思想。不管,虽然两种方法都实现了栈,但两者的性能方法有差异:

    • append()​ 和pop() 方法的时间复杂度都是 *O(1),*常数级别操作
    • 第二种实现的性能则受制于栈中的元素个数,这是因为insert(0)​ 和pop(0) 的时间复杂度都是O(n),元素越多就越慢。​

    四、用 collections.deque 实现栈

    在 Python 中,collections 模块有一个双端队列数据结构 deque,这个数据结构同样实现了 append() 和 pop() 方法:

    >>> from collections import deque
    >>> myStack = deque()
    >>> myStack.append('Apple')
    >>> myStack.append('Banana')
    >>> myStack.append('Orange')
    >>> 
    >>> myStack
    deque(['Apple', 'Banana', 'Orange'])
    >>> myStack.pop()
    'Orange'
    >>> myStack.pop()
    'Banana'
    >>>
    >>> len(myStack)
    1
    >>> myStack[0]
    'Apple'
    >>> myStack.pop()
    'Apple'
    
    >>>
    >>> myStack.pop()
    Traceback (most recent call last):
    File "", line 1, in 
    myStack.pop()
    IndexError: pop from an empty deque
    >>>

    为什么有了 list 还需要 deque?

    可能你可以看到 deque 和列表 list 对元素的操作差不多,那么为什么 Python 中有列表还增加了 deque 这一个数据结构呢?

    那是因为,Python 中的列表建立在连续的内存块中,意味着列表的元素是紧挨着存储的。

    Python中的几种栈实现及其优缺点

    这对一些操作来说非常有效,比如对列表进行索引。获取 myList[3] 的速度很快,因为 Python 确切地知道在内存中寻找它的位置。这种内存布局也允许切片在列表上很好地工作。

    毗连的内存布局是 list 可能需要花费更多时间来 .append() 一些对象。如果连续的内存块已经满了,那么它将需要获得另一个内存块,先将整体 copy 过去,这个动作可能比一般的 .append() 操作花费更多的时间。

    Python中的几种栈实现及其优缺点

    而双端队列 deque 是建立在一个双链表的基础上。在一个链接列表结构中,每个条目都存储在它自己的内存块中,并有一个对列表中下一个条目的引用。

    双链表也是如此,只是每个条目都有对列表中前一个和后一个条目的引用。这使得你可以很容易地在列表的两端添加节点。

    在一个链接列表结构中添加一个新的条目,只需要设置新条目的引用指向当前堆栈的顶部,然后将堆栈的顶部指向新条目。

    Python中的几种栈实现及其优缺点

    Python中的几种栈实现及其优缺点

    然而,这种在栈上不断增加和删除条目的时间是有代价的。获取 myDeque[3] 的速度要比列表慢,因为 Python 需要走过列表的每个节点来获取第三个元素。

    幸运的是,你很少想在栈上做随机索引元素或进行列表切片操作。栈上的大多数操作都是 push 或 pop。

    如果你的代码不使用线程,常数时间的 .append() 和 .pop() 操作使 deque 成为实现 Python 栈的一个更好的选择。

    五、用 queue.LifoQueue 实现栈

    Python 栈在多线程程序中也很有用,我们已经学习了 list 和 deque 两种方式。对于任何可以被多个线程访问的数据结构,在多线程编程中,我们不应该使用 list,因为列表不是线程安全的。deque 的 .append() 和 .pop() 方法是原子性的,意味着它们不会被不同的线程干扰。

    因此,虽然使用 deque 可以建立一个线程安全的 Python 堆栈,但这样做会使你自己在将来被人误用,造成竞态条件。

    好吧,如果你是多线程编程,你不能用 list 来做堆栈,你可能也不想用 deque 来做堆栈,那么你如何为一个线程程序建立一个 Python 堆栈?

    答案就在 queue 模块中:queue.LifoQueue。还记得你是如何学习到栈是按照后进先出(LIFO)的原则运行的吗?嗯,这就是 LifoQueue 的 "Lifo "部分所代表的含义。

    虽然 list 和 deque 的接口相似,但 LifoQueue 使用 .put() 和 .get() 来从栈中添加和删除数据。

    >>> from queue import LifoQueue
    >>> stack = LifoQueue()
    >>> stack.put('H')
    >>> stack.put('E')
    >>> stack.put('L')
    >>> stack.put('L')
    >>> stack.put('O')
    >>> stack
    
    >>> 
    >>> stack.get()
    'O'
    >>> stack.get()
    'L'
    >>> stack.empty()
    False
    >>> stack.qsize()
    3
    >>> stack.get()
    'L'
    >>> stack.get()
    'E'
    >>> stack.qsize()
    1
    >>> stack.get()
    'H'
    >>> stack.get_nowait()
    Traceback (most recent call last):
    File "", line 1, in 
    stack.get_nowait()
    _queue.Empty
    >>> 
    
    >>> stack.put('Apple')
    >>> stack.get_nowait()
    'Apple'

    与 deque 不同,LifoQueue 被设计为完全线程安全的。它的所有方法都可以在线程环境中安全使用。它还为其操作添加了可选的超时功能,这在线程程序中经常是一个必须的功能。

    然而,这种完全的线程安全是有代价的。为了实现这种线程安全,LifoQueue 必须在每个操作上做一些额外的工作,这意味着它将花费更长的时间。

    通常情况下,这种轻微的减速对你的整体程序速度并不重要,但如果你已经测量了你的性能,并发现你的堆栈操作是瓶颈,那么小心地切换到 deque 可能是值得做的。

    六、选择哪一种实现作为栈

    一般来说,如果你不使用多线程,你应该使用 deque。如果你使用多线程,那么你应该使用 LifoQueue,除非你已经测量了你的性能,发现 push 和 pop 的速度的小幅提升会带来足够的差异,以保证维护风险。

    你可以对列表可能很熟悉,但需要谨慎使用它,因为它有可能存在内存重新分配的问题。deque 和 list 的接口是相同的,而且 deque 没有线程不安全问题。

    七、总结

    本文介绍了栈这一数据结构,并介绍了在现实生活中的程序中如何使用它的情况。在文章的中,介绍了 Python 中实现栈的三种不同方式,知道了 deque 对于非多线程程序是一个更好的选择,如果你要在多线程编程环境中使用栈的话,可以使用 LifoQueue。

    ​​想了解更多关于开源的内容,请访问:​​

    ​​51CTO 开源基础软件社区​​

    ​​https://ost.51cto.com​​。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Python 数据结构
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    Postman macOS版
    Postman macOS版

    Postman是一套面向API全生命周期的开发与测试平台,可在Mac上发送和调试多种协议请求,管理集合、环境及认证信息,并完成脚本测试、模拟服务、监控、文档发布和团队协作。它适合开发、测试及运维人员使用,提供个人免费方案。

    Docker Desktop macOS版
    Docker Desktop macOS版

    Docker Desktop 是 Docker 官方为 Mac 提供的容器开发环境,集成 Docker Engine、命令行工具、Compose、Build、Kubernetes 与图形化管理界面。

    Android Studio macOS版
    Android Studio macOS版

    Android Studio 是 Google 面向安卓应用开发提供的官方集成开发环境,基于 IntelliJ IDEA 构建。它整合智能代码编辑、Gradle 构建、界面预览、设备模拟、性能分析、调试测试及 APK 分析等工具。

    Xcode macOS版
    Xcode macOS版

    Xcode 是苹果面向 Mac 提供的官方集成开发环境,将代码编辑、项目构建、SwiftUI 实时预览、设备模拟、自动化测试、断点调试、性能分析和应用分发整合在同一套工作流中,适合开发与维护 iPhone、iPad、Mac、Apple Wa

    JetBrains WebStorm macOS版
    JetBrains WebStorm macOS版

    JetBrains WebStorm 是面向 JavaScript、TypeScript 和现代 Web 技术的专业集成开发环境,可智能理解项目结构,提供代码补全、重构、错误检查、运行调试、测试及 Git 工具。

    PhpStorm macOS版
    PhpStorm macOS版

    PhpStorm 是 JetBrains 推出的专业 PHP 集成开发环境,可在 Mac 上完成代码编写、智能检查、重构、调试、测试和数据库管理。它支持主流 PHP 框架、Composer、Git、Docker 与远程解释器。

    JetBrains PyCharm macOS版
    JetBrains PyCharm macOS版

    JetBrains PyCharm 是面向 Python 开发者的集成开发环境,提供智能补全、代码检查、重构、调试、测试、版本控制及虚拟环境管理功能。Mac 版兼容 Intel 与 Apple 芯片,核心功能可免费使用。

    JetBrains IntelliJ IDEA macOS版
    JetBrains IntelliJ IDEA macOS版

    IntelliJ IDEA 是 JetBrains 推出的专业集成开发环境,重点服务于 Java、Kotlin 与 JVM 项目开发。软件集成代码补全、静态检查、重构、调试、测试、版本控制及构建工具,并可借助插件扩展语言和框架支持。

    Visual Studio Code macOS版
    Visual Studio Code macOS版

    Visual Studio Code 是微软提供的免费代码编辑器,支持 macOS,并为 Intel 与 Apple 芯片 Mac 提供适配版本。软件集代码编辑、调试、Git 源代码管理、集成终端和扩展市场于一体。

    REAPER macOS版
    REAPER macOS版

    REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。

    Adobe Audition macOS版
    Adobe Audition macOS版

    Adobe Audition 是面向播客、影视后期、音乐制作及内容创作者的专业音频工作站,提供波形精修、多轨录制与混音、频谱编辑、降噪修复、响度匹配和效果处理工具,并可与 Adobe Premiere 协同完成视频声音制作。

    Pro Tools macOS版
    Pro Tools macOS版

    Pro Tools 是 Avid 推出的专业数字音频工作站,覆盖多轨录音、无损剪辑、MIDI 编曲、插件处理、自动化混音及声音与画面同步等工作。它拥有 Intro、Artist、Studio 和 Ultimate 等方案。

    WINDOWS 更多
    PixPix 网页版
    PixPix 网页版

    PixPix 是面向品牌、卖家和内容团队的在线 AI 图片视频创作平台,提供图视频 Agent、无限画布、图片生成、视频生成、自然语言编辑及商品套图、产品精修和带货视频等电商工具。

    Postman Windows版
    Postman Windows版

    Postman 是面向 API 全生命周期的开发与协作平台。Windows 桌面版可用于构建和发送 HTTP、GraphQL、gRPC、WebSocket、MQTT 等请求,并提供环境变量、集合、脚本测试、模拟服务、监控、文档及团队工作区等

    Docker Desktop Windows版
    Docker Desktop Windows版

    Docker Desktop 为 Windows 开发者提供集成式容器环境,内置 Docker Engine、命令行工具、Compose、Build 与 Kubernetes 等组件,可在本机完成镜像构建、容器运行、日志查看和资源管理。

    Android Studio Windows版
    Android Studio Windows版

    Android Studio 是 Google 面向 Android 应用开发提供的官方集成开发环境,以 IntelliJ IDEA 为基础,集成智能代码编辑、Gradle 构建、设备模拟、界面预览、调试测试及性能分析工具,

    JetBrains WebStorm Windows版
    JetBrains WebStorm Windows版

    WebStorm 是 JetBrains 面向 JavaScript、TypeScript 和现代 Web 技术打造的集成开发环境。它提供项目级代码分析、智能补全、安全重构、导航搜索,并集成调试、测试、终端、Git 与常用前端工具,

    JetBrains PhpStorm Windows版
    JetBrains PhpStorm Windows版

    PhpStorm 是 JetBrains 面向 PHP 与现代 Web 开发打造的专业集成开发环境,提供代码补全、静态检查、重构、调试、测试、数据库、版本控制及前端语言支持。Windows 用户可直接下载安装程序,

    JetBrains PyCharm Windows版
    JetBrains PyCharm Windows版

    PyCharm 是 JetBrains 推出的 Python 集成开发环境,提供智能代码补全、错误检查、重构、调试、测试、Git、终端及 Jupyter Notebook 支持。统一版安装后可体验 30 天 Pro 功能,

    JetBrains IntelliJ IDEA Windows版
    JetBrains IntelliJ IDEA Windows版

    JetBrains IntelliJ IDEA 是以 Java、Kotlin 和 JVM 项目为核心的专业集成开发环境,提供智能补全、代码检查、安全重构、调试、测试、版本控制及构建工具集成。统一发行版的核心功能可免费用于商业和非商业项目,

    Visual Studio Code Windows版
    Visual Studio Code Windows版

    Visual Studio Code 是微软推出的免费代码编辑器,Windows 版集成智能补全、代码导航、调试、终端和版本控制,并可通过扩展添加语言、格式化及远程开发能力。它启动较快、配置灵活,

    REAPER Windows版
    REAPER Windows版

    REAPER 是 Cockos 推出的数字音频工作站,适用于录音、MIDI 编曲、音频编辑、混音、母带制作及声音设计。软件安装包小巧,支持多轨录制、灵活路由、自动化、第三方插件和脚本扩展,并提供完整功能的 60 天免费评估期。

    Adobe Audition Windows版
    Adobe Audition Windows版

    Adobe Audition 是面向播客、影视后期、广播与音乐制作的专业音频工作站,提供波形编辑、多轨混音、频谱分析、录音、降噪修复和效果处理等功能。Windows 版通过 Adobe Creative Cloud 安装和管理,

    Pro Tools Windows版
    Pro Tools Windows版

    Pro Tools 是 Avid 推出的专业数字音频工作站,提供多轨录音、音频剪辑、MIDI编曲、插件处理、自动化混音及影视声音制作能力。它适合音乐人、录音师、制作人和音频后期团队使用,并提供免费入门版、订阅方案及永久授权选择。