数据结构与算法之美 | 栈

news2024/11/16 13:30:04
  • 栈结构:后进者先出,先进者后出

  • 栈是一种“操作受限”的线性表

  • 当某个数据集合只涉及在一端插入和删除数据,并且满足后进先出、先进后出的特性,这时我们就应该首选“栈”这种数据结构

栈的实现

  • 使用数组实现:顺序栈
class ArrayStack:
    """使用数组实现一个顺序栈"""

    def __init__(self):
        '''
        初始化顺序栈

        参数:
            无

        返回值:
            无
        '''
        
        self.items = []

    def push(self, item):
        '''
        入栈操作

        参数:
            item (任意类型): 待入栈的值

        返回值:
            无
        '''
        self.items.append(item)

    def pop(self):
        '''
        出栈操作

        参数:
            无

        返回值:
            待出栈的值
        '''
        if not self.is_empty():
            return self.items.pop()

    def is_empty(self):
        '''
        检查栈是否为空

        参数:
            无

        返回值:
            bool: 如果栈为空则返回True,否则返回False
        '''
        return len(self.items) == 0

  • 使用链表实现:链式栈
class Node:
    '''维护链表节点'''
    def __init__(self, value):
        '''
        初始化链表节点

        参数:
            value (任意类型): 节点的值

        返回值:
            无
        '''
        # 节点的值
        self.value = value
        # 指向下一个节点的指针
        self.next = None

class Stack:
    '''进行出栈或入栈操作'''
    def __init__(self):
        '''
        初始化栈

        参数:
            无

        返回值:
            无
        '''
        # 栈顶节点
        self.top = None

    def push(self, value):
        '''
        入栈操作

        参数:
            value (任意类型): 要入栈的值

        返回值:
            无
        '''
        if self.top is None:
            self.top = Node(value)
        else:
            # 创建新节点
            new_node = Node(value)
            # 将新节点指向当前的栈顶节点
            new_node.next = self.top
            # 更新栈顶节点为新节点
            self.top = new_node

    def pop(self):
        '''
        出栈操作

        参数:
            无

        返回值:
            出栈的节点的值
        '''
        if self.top is None:
            return None
        else:
            # 弹出栈顶节点
            popped_node = self.top
            # 更新栈顶节点为下一个节点
            self.top = self.top.next
            # 将弹出的节点从链表中断开
            popped_node.next = None
            # 返回弹出节点的值
            return popped_node.value

栈的应用

函数调用栈

操作系统给每个线程分配了一块独立的内存空间,这块内存被组织成“栈”这种结构, 用来存储函数调用时的临时变量。每进入一个函数,就会将临时变量作为一个栈帧1入栈,当被调用函数执行完成,返回之后,将这个函数对应的栈帧出栈。

def main():
    '''
    主函数,用于执行程序的主要逻辑

    参数:
        无

    返回值:
        int: 表示程序执行结果的返回值
    '''
    a = 1
    ret = 0
    res = 0

    # 调用add函数,将返回值赋给ret变量
    ret = add(3, 5)

    # 计算a和ret的和,将结果赋给res变量
    res = a + ret

    # 打印res的值
    print(res)

    return 0


def add(x, y):
    '''
    将两个数字相加

    参数:
        x (int): 第一个数字
        y (int): 第二个数字

    返回值:
        int: 两个数字的和
    '''
    sum = 0

    # 计算x和y的和,将结果赋给sum变量
    sum = x + y

    return sum


if __name__ == '__main__':
    # 调用main函数
    main()

img

能否使用其他数据结构实现函数调用功能?

  • 虽然其他数据结构也可以用来保存临时变量,但是它们的实现可能不如栈那么高效
  • 例如,使用链表来保存上下文信息,需要在插入和删除元素时遍历链表,时间复杂度为O(n),而使用栈的时间复杂度为O(1)。因此,栈是最常用的函数调用栈的实现方式。

表达式求值

编译器通过两个栈来实现的。其中一个保存操作数的栈,另一个是保存运算符的栈。

  1. 我们从左向右遍历表达式,当遇到数字,我们就直接压入操作数栈;
  2. 当遇到运算符,就与运算符栈的栈顶元素进行比较。如果比运算符栈顶元素的优先级高,就将当前运算符压入栈;
  3. 如果比运算符栈顶元素的优先级低或者相同,从运算符栈中取栈顶运算符,从操作数栈的栈顶取 2 个操作数,然后进行计算,再把计算完的结果压入操作数栈,继续比较。

img

检查括号是否匹配

假设表达式中只包含三种括号:

  • 圆括号 ()

  • 方括号[]

  • 花括号{}

它们可以任意嵌套。比如,{[] ()[{}]}[{()}([])]等都为合法格式,而{[}()][({)]为不合法的格式。

那么如何检查括号是否合法?

  1. 我们用栈来保存未匹配的左括号,从左到右依次扫描字符串。

  2. 当扫描到左括号时,则将其压入栈中;当扫描到右括号时,从栈顶取出一个左括号。如果能够匹配,比如 () 匹配,[]匹配,{}匹配,则继续扫描剩下的字符串。如果扫描的过程中,遇到不能配对的右括号,或者栈中没有数据,则说明为非法格式。

  3. 当所有的括号都扫描完成之后,如果栈为空,则说明字符串为合法格式;否则,说明有未匹配的左括号,为非法格式。

实现浏览器的前进和后退功能

  • 使用两个栈,X 和 Y。
  • 我们把首次浏览的页面依次压入栈 X,当点击后退按钮时,再依次从栈 X 中出栈,并将出栈的数据依次放入栈 Y。当我们点击前进按钮时,我们依次从栈 Y 中取出数据,放入栈 X 中。
  • 当栈 X 中没有数据时,那就说明没有页面可以继续后退浏览了。当栈 Y 中没有数据,那就说明没有页面可以点击前进按钮浏览了。

JVM中的堆栈和栈的区别是什么?

JVM 中的“栈”和数据结构中的“栈”是类似的,都是一种后进先出(LIFO)的数据结构。但是它们的实现和使用方式是不同的。

在JVM中,每个线程都有一个私有的栈,用于存储方法调用时的局部变量和操作数栈。当一个方法被调用时,会在栈上创建一个新的栈帧,用于存储该方法的局部变量和操作数栈等信息。当方法返回时,该方法对应的栈帧就会被销毁。因此,JVM中的“栈”主要用于方法调用和返回,以及存储线程私有的数据。

在计算机科学中,栈通常指的是一种数据结构,它是一种后进先出(LIFO)的数据结构,只能在栈顶进行插入和删除操作。栈通常用于函数调用时保存临时变量和返回地址,以及递归等算法实现中

Leetcode:栈习题

题目:

  • 20
  • 155
  • 232
  • 844
  • 224
  • 682
  • 496

  1. 每当一个函数被调用时,都会创建一个新的栈帧(Stack Frame),用于保存该函数的局部变量、参数、返回地址等信息 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/634846.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】二叉树(一)

目录 一、树的概念及结构 1、树的概念 2、树的相关概念 3、树的表示 二、二叉树概念及结构 1、二叉树的概念 2、特殊二叉树 3、二叉树的性质 4、二叉树的存储结构 4.1 顺序存储结构 4.2 链式存储结构 三、二叉树顺序结构及实现 1、二叉树的顺序结构 2、堆的概念及结构 3、堆…

OMG--RTPS(Real Time Publish Subscribe Protocol)

OMG--RTPS(Real Time Publish Subscribe Protocol) 1 概述2 内容缩写DDS 有线协议的要求RTPS 有线协议The RTPS Platform Independent Model (PIM)The Structure ModuleThe Messages ModuleThe Behavior ModuleThe Discovery Module The RTPS Platform S…

Xuperchain多节点网络搭建+加节点+测试

环境准备 创建网络部署环境 # 在xuperchain目录执行 make testnet 种子节点 # 查看node1节点连接地址netURL cd node1 ./bin/xchain-cli netURL preview # 得到如下结果,实际使用时,需要将ip配置节点的真实ip,port配置成 /ip4/{{ip}}/tcp/{{port}}/p2p/Qmf2HeHe4sspGkfR…

深度学习应用篇-计算机视觉-OCR光学字符识别[7]:OCR综述、常用CRNN识别方法、DBNet、CTPN检测方法等、评估指标、应用场景

【深度学习入门到进阶】必看系列,含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍:【深度学习入门到进阶】必看系列,含激活函数、优化策略、损失函数、模型调优、归一化…

上课补充的知识

题目 char类型的默认值是\u0000 数组的创建方式 数组的遍历 遍历:从头到尾,依次访问数组每一个位置,获取每一个位置的元素.形式如下: 我们通过数组的下标操作数组,所以for循环变量操作的也是数组下标 开始:开始下标0 结束:结束下标length-1 如何变化: 语法: for…

大学结束啦!!!

前言:相信看到这篇文章的小伙伴都或多或少有一些编程基础,懂得一些linux的基本命令了吧,本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python:一种编程语言&…

神舟笔记本“性能、娱乐、省电、安静”模式之间的区别

前言:主要是对比神舟笔记本电脑“性能、娱乐、省电、安静”模式之间的区别 工具及硬件 名称版本号电脑Z8D6 2.5k屏鲁大师6.1023.xxx 之所以使用鲁大师,主要是为了节省时间.另外仅仅只是为了做横向对比,不需要太专业的工具。 实验中有两个变…

六级备考6天|CET-6|听力第一二三四讲|复习回顾|长对话篇章|14:00~16:30

长对话 篇章 目录 听写笔记 练习讲义 听写笔记 1. 听力策略 听前:读题——分析文章——预测题目 听中:划出听到的内容——对应程度高为正确选项 听后:不听题目——往下读题 2. 重点词汇 proofread / ˈpruːfriːd / …

CodeWhisperer插件使用体验

官方教程点击跳转 使用工具 1.vscode 2.插件(AWS Toolkit),免费使用 安装以后如何使用 1.首先要有一个aws账号 2.插件下载好以后登录aws账号,我们主要用这款插件的CodeWhisperer这个功能,其它的自行看官方教程了解。 注意事项:我们在从vs…

杭州互联网医疗Java实习一面

目录 1.java集合知道哪些2.ArrayList和LinkedList插入效率对比3.HashMap的底层结构4.HashMap怎么实现线程安全4.介绍下reentrantlock5.Redis分布式锁的实现原理7.知道哪些排序算法8.快排的原理9.Spring的AOP作用和原理10.MySQL的InnoDB索引结构11.网络中TCP和UDP的区别12.JVM的…

delphi 调用youtube-dl命令,下载youtube视频,原理及源代码

一、概要 1、Youtube-dl工具 强大的视频下载命令行工具Youtube-dl项目由Ricardo Garcia创建于2008年,源代码由Python编写,托管在GitHub上, 最初仅支持YouTube,但随着项目的发展,也开始支持其他视频网站,优势…

如何优化selenium webdriver的执行速度

目录 前言 在page_source中断言text比直接使用text属性断言要快 元素越具体,获取text的速度越快 使用变量去缓存没有变化的元素 快速在文本框中输入大文本 使用动态等待进行动态/AJAX 操作而不是固定睡眠 最后 前言 让自动化测试脚本正常工作只是自动化测试的…

微信小程序的自动化测试框架Minium详解,10分钟掌握

目录 前言 minium 是为小程序专门开发的自动化框架 文档使用 框架依赖运行环境部署 使用 打开工具 特别说明: 总结: 前言 微信发布了小程序的自动化测试框架Minium,提供了多种运行验证方式,其特点: 支持一套脚…

Alloy Tutorial(2)LastPass; cacheMemory

文章目录 LastPass整体 solution 代码: cacheMemory LastPass module LastPass/** LastPass password map** A simple example to explain basics of Alloy. ** The PassBook keeps track of a set of users passwords for a set of URLs. * For each User/URL pai…

【阿里云】第一次进行域名注册、备案以及使用全过程

前言 随着ChatGPT的爆火,让我直面感受到了一项技术的突破可以产生堪比原子弹爆炸的威力,因而在品尝过ChatGPT带来的便利与甜头后,就一直在跟进,同时也在能力范围内,让数十位朋友使用上了ChatGPT 前段时间&#xff0c…

ftrace学习 —— user_events的用法

参考 https://docs.kernel.org/trace/user_events.html 测试程序 samples/user_events/example.c tools/testing/selftests/user_events/ftrace_test.c 正文 通过user_event可以实现对应用程序的跟踪,类似linux内核中的tracepoint那样。相似的方法还有借助/sys…

走进docker

一、Docker 概述 1、Docker的概念 • Docker是一个开源的应用容器引擎,基于go语言开发并遵循了apache2.0协议开源 • Docker是在Linux容器里运行应用的开源工具,是一种轻量级的“虚拟机” • Docker 的容器技术可以在一台主机上轻松为任何应用创建一…

异常数据检测 | Python实现基于高斯概率分布的异常数据检测

文章目录 文章概述模型描述源码分享学习小结参考资料文章概述 高斯分布也称为正态分布。它可以被用来进行异常值检测,不过我们首先要假设我们的数据是正态分布的。不过这个假设不能适应于所有数据集。但如果我们做了这种假设那么它将会有一种有效的方法来发现异常值。 模型描述…

asp.net审计项目管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net审计项目管理系统 是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使用c#语言 开发 二、功能介绍 (1)科室管理&…

GIT远程仓库(随笔)

目录 前言 一、GIt常见命令 二、概念原理 三、常见的代码托管平台 四、配置SSH公钥 五、操作 1、注册账号 2、在gitee中,创建远程仓库 3、Git命令创建本地仓库 4、Git命令创建第一个版本提交 5、Git命令添加远程仓库 6、推送 7、修改开源项目 ​编辑 8、…