数据结构 | 基本数据结构——栈

news2024/12/27 3:56:39

目录

一、线性数据结构

二、栈

2.1 何谓栈

2.2 栈抽象数据类型

2.3 用Python实现栈

2.4 匹配括号

2.5 普通情况:匹配符号

2.6 将十进制数转换成二进制数

3.7 前序、中序和后序表达式

3.7.1 从中序到后序的通用转换法

3.7.2 计算后序表达式


一、线性数据结构

栈、队列、双端队列和列表都是有序的数据集合,其元素的顺序取决于添加顺序或移除顺序。一旦某个元素被添加进来,它与前后元素的相对位置将保持不变。这样的数据集合经常被称为线性数据结构。

线性数据结构可以看作有两端。真正区分线性数据结构的是元素的添加方式和移除方式,尤其是添加操作和移除操作发生的位置。举例来说,某个数据结构可能只允许在一端添加新元素,有些则允许从任意一端移除元素。

二、栈

2.1 何谓栈

栈有时也被称作“下推栈 ”。它是有序集合,添加操作和移除操作总发生在同一端,即“顶端”,另一端则被称为“底端”。

栈中的元素离底端越近,代表其在栈中的时间越长,因此栈的底端具有非常重要的意义。最新添加的元素将被最先移除。这种排序原则被称作LIFO,即后进先出。它提供了一种基于在集合中的时间来排序的方式。最近添加的元素靠近顶端,旧元素靠近底端。

2.2 栈抽象数据类型

栈抽象数据类型由下面的结构和操作定义。如前所述,栈是元素的有序集合,添加操作与移除操作都发生在其顶端。栈的操作顺序是LIFO,它支持以下操作。

  • Stack()创建一个空栈。它不需要参数,且会返回一个空栈。
  • push(item)将一个元素添加到栈的顶端。它需要一个参数item,且无返回值。
  • pop()将栈顶端的元素移除。它不需要参数,但会返回顶端的元素,并且修改栈的内容。
  • peek()返回栈顶端的元素,但是并不移除该元素。它不需要参数,也不会修改栈的内容。
  • isEmpty()检查栈是否为空。它不需要参数,且会返回一个布尔值。
  • size()返回栈中元素的数目。它不需要参数,且会返回一个整数。

2.3 用Python实现栈

抽象数据类的实现被称为数据结构。

以下代码是栈的实现,它假设列表的尾部是栈的顶端。当栈增长时(即进行push操作),新的元素会被添加到列表的尾部,pop操作同样会修改这一端。

class Stack:
    def __init__(self):
        self.items=[]
        
    def isEmpty(self):
        return self.items==[]
    
    def push(self,item):
        self.items.append(item)
    
    def pop(self):
        return self.items.pop()
    
    def peek(self):
        return self.items[len(self.items)-1]
    
    def size(self):
        return len(self.items)

接下来展示上述代码中的栈操作及其返回结果。

s=Stack()
print(s.isEmpty())

s.push(4)
s.push('dog')
print(s.peek())

s.push(True)
print(s.size())

print(s.isEmpty())

s.push(8.4)
print(s.pop())

print(s.pop)

print(s.size)

也可以选择将列表的头部作为栈的顶端。不过在这种情况下,便无法直接使用pop方法和append方法,而必须使用pop方法和insert方法显式地访问下标为0的元素,即列表中的第1个元素。代码如下:

class Stack:
    def __init__(self):
        self.items=[]

    def isEmpty(self):
        return self.items==[]

    def push(self,item):
        self.items.insert(0,item)

    def pop(self):
        return self.items.pop(0)

    def peek(self):
        return self.items[0]

    def size(self):
        return len(self.items)

尽管上述两种实现都可行,但是二者在性能方面肯定有差异。append方法和pop()方法的时间复杂度都是O(1),这意味着不论栈中有多少个元素,第一种实现中的push操作和pop操作都会在恒定时间内完成。第二种实现的性能则受制于栈中的元素个数,这是因为insert(0)和pop(0)的时间复杂度都是O(n),元素越多越慢。

2.4 匹配括号

由一个空栈开始,从左到右依次处理括号。如果遇到左括号,便通过push操作将其加入栈中,以此表示稍后需要有一个与之匹配的右括号。反之,如果遇到右括号,就调用pop操作。只要栈中的所有左括号都能遇到与之匹配的右括号,那么整个括号串就是匹配的;如果栈中有任何一个左括号找不到与之匹配的右括号,则括号串就是不匹配的。在处理完匹配的括号串之后,栈应该是空的。代码如下:

from pythonds.basic import Stack

def parChecker(symbolString):
    s=Stack()
    balanced=True
    index=0
    while index<len(symbolString) and balanced:
        symbol=symbolString[index]
        if symbol=="(":
            s.push(symbol)
        else:
            if s.isEmpty():
                balanced=False
            else:
                s.pop()
        index=index+1
    if balanced and s.isEmpty():
        return True
    else:
        return False

2.5 普通情况:匹配符号

from pythonds.basic import Stack

def parChecker(symbolString):
    s=Stack()
    balanced=True
    index=0
    while index<len(symbolString) and balanced:
        symbol=symbolString[index]
        if symbol in "([{":
            s.push(symbol)
        else:
            if s.isEmpty():
                balanced=False
            else:
                top=s.pop()
                if not matches(top,symbol):
                    balanced=False
        index=index+1
    if balanced and s.isEmpty():
        return True
    else:
        return False

def matches(open,close):
    opens="([{"
    closers=")]}"
    return opens.index(open)==closers.index(close)

2.6 将十进制数转换成二进制数

将十进制数转换成二进制数采用的是“除以2”算法。“除以2”算法假设待处理的整数大于0.它用一个简单的循环不停地将十进制数除以2,并且记录余数。第一次除以2的结果能够用于区分偶数和奇数。如果是偶数,则余数为0,因此个位上的数字是0;如果是奇数,则余数为1,因此个位上的数字是1.可以将要构建的二进制数看成一系列数字;计算出的第一个余数是最后一位。这体现出了反转特性,因此用栈来解决问题是合理的。

from pythonds.basic import Stack

def divideBy2(decNumber):
    remstack=Stack()
    while decNumber>0:
        rem=decNumber%2
        remstack.push(rem)
        decNumber=decNumber//2
    binString=""
    while not remstack.isEmpty():
        binString=binString+str(remstack.pop())
    return binString

将十进制数转换成任意进制数的代码如下:

from pythonds.basic import Stack

def baseConverter(decNumber,base):
    digits="0123456789ABCDEF"
    remstack=Stack()
    while decNumber>0:
        rem=decNumber%base
        remstack.push(rem)
        decNumber=decNumber//base
    newString=""
    while not remstack.isEmpty():
        newString=newString+digits[remstack.pop()]
    return newString

3.7 前序、中序和后序表达式

3.7.1 从中序到后序的通用转换法

假设中序表达式是一个以空格分隔的标记串。其中,运算符标记有*、/、+和-,括号标记有(和),操作数标记有A、B、C等。下面的步骤会生成一个后序标记串。

(1)创建用于保存运算符的空栈opstack,以及一个用于保存结果的空列表。

(2)从左往右扫描这个标记列表。

  • 如果标记是操作数,将其添加到结果列表的末尾。
  • 如果标记是左括号,将其压入opstack栈中。
  • 如果标记是右括号,反复从opstack栈中移除元素,直到移除对应的左括号。将从栈中取出的每一个运算符都添加到结果列表的末尾。
  • 如果标记的是运算符,将其压入opstack栈中。但是,在这之前,需要先从栈中取出优先级更高或相同的运算符,并将它们添加到列表的末尾。

(3)当处理完输入表达式以后,检查opstack。将其中所有残留的运算符全部添加到结果列表的末尾。

为了在Python中实现这一算法,我们使用一个叫做prec的字典来保存运算符的优先级值。该字典把每一个运算符都映射成一个整数。通过比较对应的整数,可以确定运算符的优先级。左括号的优先级值最小。这样一来,任何与左括号比较的运算符都会被压入栈中。我们也将导入string模块,它包含一系列预定义变量。本例使用一个包含所有大写字母的字符串(string.ascii_uppercase)来代表所有可能出现的操作数。代码如下:

from pythonds.basic import Stack
import string

def infixToPostfix(infixexpr):
    prec={}
    prec['*']=3
    prec['/']=3
    prec['+']=2
    prec['-']=2
    prec['(']=1

    opStack=Stack()
    postfixList=[]

    for token in infixexpr:
        if token in string.ascii_uppercase:
            postfixList.append(token)
        elif token=='(':
            opStack.push(token)
        elif token==')':
            topToken=opStack.pop()
            while topToken != '(':
                postfixList.append(topToken)
                topToken=opStack.pop()
        else:
            while (not opStack.isEmpty()) and (prec[opStack.peek()]>=prec[token]):
                postfixList.append(opStack.pop())
            opStack.push(token)

    while not opStack.isEmpty():
        postfixList.append(opStack.pop())

    return " ".join(postfixList)

print(infixToPostfix("(A+B)*(C+D)"))

3.7.2 计算后序表达式

假设后序表达式是一个以空格分隔的标记串。其中,运算符标记有*、/、+、-,操作数标记是一位的整数值。结果是一个整数。

(1)创建空栈operandStack.

(2)使用字符串方法split将输入的后序表达式转换成一个列表。

(3)从左往右扫描这个标记列表。

  • 如果标记是 操作数,将其转换成整数并且压入operandStack栈中。

如果标记是运算符,从operandStack栈中取出两个操作数。第一次取出右操作数,第二次取出左操作数。进行相应的算数运算,然后将运算结果压入operandStack栈中。

(4)当处理完输入表达式时,栈中的值就是结果。将其从栈中返回。

from pythonds.basic import Stack
def postfixEval(postfixExpr):
    operandStack=Stack()

    tokenList=postfixExpr.split()

    for token in tokenList:
        if token in "0123456789":
            operandStack.push(int(token))
        else:
            operand2=operandStack.pop()
            operand1=operandStack.pop()
            result=doMath(token,operand1,operand2)
            operandStack.push(result)

    return operandStack.pop()

def doMath(op,op1,op2):
    if op=="*":
        return op1*op2
    elif op=="/":
        return op1/op2
    elif op=="+":
        return op1+op2
    else:
        return op1-op2

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

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

相关文章

Docker 镜像操作

Docker镜像操作 我们已经介绍了容器操作,今天来了解下 Docker镜像 以及 镜像操作 。让我们一起开启镜像之旅吧。 Docker镜像 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库…

QML 往图表添加文字显示

需求&#xff1a; 需要在图表的某几个点上&#xff0c;添加相应的文字显示。效果如下: 主要是&#xff0c;如何将坐标进行转化为图表的相对坐标&#xff0c;然后动态创建文本后&#xff0c;将转换坐标设置到Text中。 演示demo。需要点击Text按钮后&#xff0c;图表显示。 impo…

如何为WordPress博客网站配置自己购买的域名,并且公网可访问?

文章目录 如何为WordPress博客网站配置自己购买的域名&#xff0c;并且公网可访问&#xff1f;前置条件&#xff1a;具体操作步骤如下&#xff1a;步骤1: 后台预留自定义域名步骤2: 配置您的域名DNS解析步骤3: 测试域名解析步骤4: 在前台终端测试运行步骤4: 修改cpolar配置文件…

等保测评需要做几次?做一次以后还需要做吗?

虽然我国等保政策已经严格落地执行了&#xff0c;但不少企业对于等保测评相关政策还不是很了解&#xff0c;有人在问&#xff0c;等保测评需要做几次&#xff1f;做一次以后还需要做吗&#xff1f;今天我们就来简单回答一下吧&#xff01; 等保测评需要做几次&#xff1f;做一…

【无公网IP】在公网环境下Windows远程桌面Ubuntu 18.04

文章目录 一、 同个局域网内远程桌面Ubuntu1. 更新软件仓库2. 安装支持包3. 安装XFCE4桌面环境4. 安装XRDP5. 环境设置5.1 XFCE桌面配置5.2 在配置文件中&#xff0c;加入XFCE会话 6 重启服务7. 查看IP地址8. 使用Windows远程桌面连接 二、公网环境系统远程桌面Ubuntu1. 注册cp…

如何恢复U盘数据 U盘数据恢复图文教程

u盘是我们日常生活中很常用到的存储设备&#xff0c;我们会经常用到u盘去保存重要的数据或文件&#xff0c;但是使用的频率多了&#xff0c;有时候也会因为一些原因&#xff0c;出现各种各种的异常问题&#xff0c;就比如说u盘数据丢失。那&#xff0c;当u盘数据丢失后还可以恢…

金山云与平凯星辰达成全面战略合作 技术创新模式助力企业数字化转型

在新型经济形态下&#xff0c;云计算成为数字化发展的必然方向&#xff0c;互联网、金融、医疗等行业的企业纷纷加速数字经济转型。2023 年&#xff0c;金山云与企业级开源分布式数据库厂商平凯星辰&#xff08;PingCAP&#xff09;达成战略合作&#xff0c;顺应技术创新与行业…

python 之 浮点数精度丢失例如:0.1 + 0.2,产生的原因、问题的推导、解决的方案

一、背景 计算机基本上使用二进制数字&#xff0c;即 0 或 1表示&#xff1b; 十进制&#xff1a; 1 / 3 0.3333333333… 无限循环的情况 浮点数的总数是无限且不可数的&#xff0c;浮点数在计算机占用的内存是有限的&#xff0c;如果表示计算机内存则占满 不可能用有限的内存…

Kafka 入门到起飞系列 - 到底什么是再平衡?谁来执行再平衡呢?什么是组协调器呢?

再平衡&#xff08;Rebalance&#xff09; 本质上是一种协议&#xff0c;规定了一个消费组中所有消费者如何达成一致来分配订阅主题的每个分区 其实就是建立分区和消费者映射关系的这么一个过程&#xff0c;最终主题下的一个分区只会分配给一个消费者 比如有10个分区&#xff…

个人博客系统 -- 登录页面添加图片验证码

目录 1. 功能展示 2. 前段代码 3. 后端代码 1. 功能展示 在登录页面添加验证码登录 1. 检测到没有输入验证码或者输入的验证码错误时,进行弹窗提示.并且刷新当前验证码图片 2. 点击验证码进行刷新 2. 前段代码 1. 添加验证码标签,在密码的下面,在login.html进行修改 主要…

多模态预训练 + 自监督学习 + 下游任务介绍

预训练 1&#xff09;特征提取要解决的问题是怎么分别量化文字和图像&#xff0c;进而送到模型学习? 特征抽取&#xff1a; 文本&#xff1a;倾向于bert等大模型 图像&#xff1a;神经网络&#xff0c;VIT等 2&#xff09;特征融合要解决的问题是怎么让文字和图像的表征交…

基于Java+SpringBoot+vue前后端分离社区医院信息平台设计实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

Hadoop_HDFS_常见的文件组织格式与压缩格式

参考资料 1. HDFS中的常用压缩算法及区别_大数据_王知无_InfoQ写作社区 2. 本文主要介绍下HDFS上的常见文件格式和压缩格式 总结 : HDFS 中常见的文件存储格式 textfile &#xff1a;行式存储格式sequencefile &#xff1a;行式存储格式orc &#xff1a;列式存储格式, 支…

Deployment 升级应用2

上次我们说到自己手动的做使用 RS 的方式来升级 pod &#xff0c;感觉还是蛮复杂的&#xff0c;并且容易弄错&#xff0c;实际生产过程中&#xff0c;肯定不会这样来弄&#xff0c;很危险 那么今天我们来分享 Deployment 的方式来显示的升级应用吧 Deployment 的方式升级应用…

3dmax崩溃后如何恢复文件?

当意外或突然关闭 3ds Max 场景时&#xff0c;有时会出现恢复 3ds Max 场景的问题。在处理任何项目的过程中&#xff0c;有时需要恢复 3ds Max 场景&#xff0c;为此在专用文件夹中创建备份副本。如果您使用的是 Windows 操作系统并且未更改项目位置或不知道项目位置&#xff0…

如何通过nginx代理实现外网访问内网mysql或oracle数据库

项目开发部署中经常会遇到MySQL或Oracle数据库安装在内网&#xff0c;而我们的应用服务只能部署在外网&#xff0c;如果实现外网服务访问连接内网的数据库呢&#xff1f;本次介绍如何通过Nginx配置实现外网访问内网数据库。 1、前置机服务器 首先要保证有一台前置机服务器既可…

为Android构建现代应用——主体结构

创建Screents和ViewModels 在前面的章节中&#xff0c;我们已经分析了OrderNow项目的理论概念和我们将赋予的组织。 在本章中&#xff0c;我们将开始实现初始结构和模板&#xff0c;这将联接每一个应用程序的部分。 首先将添加以下带有各自视图模型的主屏幕&#xff1a; •…

到底什么是前后端分离

目录 Web 应用的开发主要有两种模式&#xff1a; 前后端不分离 前后端分离 总结 Web 应用的开发主要有两种模式&#xff1a; 前后端不分离 前后端分离 理解它们的区别有助于我们进行对应产品的测试工作。 前后端不分离 在早期&#xff0c;Web 应用开发主要采用前后端不…

“云上新气象”,VDI+IDV混合部署,麒麟信安云正式上线某市气象局!

阴晴冷暖&#xff0c;风云变幻&#xff0c;气象与人们的生活密切相关&#xff0c;气象局信息系统的智慧高效运营对于提升灾害防御能力、城市气象观测等方面具有重要作用&#xff0c;随着气象业务范围的不断扩展&#xff0c;气象局的信息化建设与数字化转型也亟需提上日程。 走…

【Solr】Solr搜索引擎使用

文章目录 一、什么是Solr?二 、数据库本身就支持搜索啊,干嘛还要搞个什么solr?三、如果我们想要使用solr那么首先我们得安装它 一、什么是Solr? 其实我们大多数人都使用过Solr,也许你不会相信我说的这句话,但是事实却是如此啊 ! 每当你想买自己喜欢的东东时,你可能会打开某…