Python数据结构与算法中的栈详解(2)
作者:姜学迁 发布时间:2022-02-11 07:00:51
匹配括号
接下来,我们使用栈解决实际的计算机科学问题。
比如我们都写过这样所示的算术表达式, ( 5 + 6 ) ∗ ( 7 + 8 ) / ( 4 + 3 ) (5 + 6) * (7 + 8) / (4 + 3) (5+6)∗(7+8)/(4+3),其中的括号用来改变计算顺序,或提升运算优先级。
匹配括号是指每一个左括号都有与之对应的一个右括号,并且括号对有正确的嵌套关系。
正确的嵌套关系: ( ( ) ( ) ( ) ( ) ) (()()()()) (()()()())、 ( ( ( ( ) ) ) ) (((()))) (((())))、 ( ( ) ( ( ( ) ) ( ) ) ) (()((())())) (()((())()))
错误的嵌套关系: ( ( ( ( ( ( ( ) ) ((((((()) ((((((())、 ( ) ) ) ())) ()))
我们的挑战就是编写一个算法,它从左到右读取一个括号串(不包括其他数字与运算符),然后判断其中的括号是否匹配。
为了解决这个问题, 需要注意到一个重要现象。当从左到右处理括号时,最右边的无匹配左括号必须与接下来遇到的第一个右括号相匹配。并且,在第一个位置的左括号可能要等到处理至最后一个位置的右括号时才能完成匹配。而且右括号的出现顺序,与其相匹配的左括号的出现顺序相反。这一规律暗示着能够运用栈来解决括号匹配问题。
一旦认识到用栈来保存括号,算法编写起来就会十分容易。
由一个空栈开始,从左往右依次处理括号。如果遇到左括号,便通过栈的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 parChecker(symbolString):
s = Stack() # 构造栈
balanced = True # 匹配标志 默认为True 表示匹配
index = 0 # 索引 用来取字符
# 当 索引小于字符串的长度 并且 匹配标志为True 时
while index < len(symbolString) and balanced:
# 取字符串当前位的字符
symbol = symbolString[index]
# 如果当前字符为 左括号 则入栈
if symbol == '(':
s.push(symbol)
# 如果当前字符 不是左括号(那当前就是右括号)
else:
# 并且栈是空的
if s.isEmpty():
# 匹配标志设置为 False 表示匹配失败(孤零零的右括号)
balanced = False
# 栈不是空的 抵消栈顶的左括号
else:
s.pop()
# 索引向后移动一位
index = index + 1
# 循环结束 如果匹配成功 并且 栈空了
if balanced and s.isEmpty():
return True
else:
return False
注意,balanced 的初始值是True,这是因为一开始没有任何理由假设其为False 。如果当前的符号是左括号,它就会被压入栈中(第27行)。注意第36行,仅通过pop()将一个元素从栈顶移除。由于移除的元素一定是之前遇到的左括号,因此并没有用到pop()的返回值。在第42~45行, 只要所有括号匹配并且栈为空,函数就会返回True ,否则返回False。
匹配符号
符号匹配是许多编程语言中的常见问题,括号匹配问题只是它的一个特例。我们已经会了匹配括号的方法,那么现在我们来试试匹配符号。
匹配符号是指正确地匹配和嵌套左右对应的符号。
例如,在Python中,方括号“[”和“]”用于列表;花括号“{”和“}”用于字典;括号“(”和“)”用于元组和算术表达式。只要保证左右符号匹配,就可以混用这些符号。以下符号串是匹配的,其中不仅每一个左符号都有一个右符号与之对应,而且两个符号的类型也是一致的。
{ { ( [ ] [ ] ) } ( ) }
[ [ { { ( ( ) ) } } ] ]
[ ] [ ] [ ] ( ) { }
以下符号则是不匹配的:
( [ ) ]
( ( ( ) ] ) )
[ { ( ) ]
要处理新类型的符号,我们扩展上面的括号匹配检测代码。
即每一个左符号都将被压入栈中,以待之后出现对应的右符号。
唯一的区别在于,当出现右符号时,必须先检测其类型是否与栈顶的左符号类型相匹配。如果两个符号不匹配,那么整个符号串也就不匹配。同样,如果整个符号串处理完成并且栈是空的,那么就说明所有符号正确匹配。
代码实现如下:
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 parChecker(symbolString):
s = Stack() # 构造栈
balanced = True # 匹配标志 默认为True 表示匹配
index = 0 # 索引 用来取字符
# 当 索引小于字符串的长度 并且 匹配标志为True 时
while index < len(symbolString) and balanced:
# 取字符串当前位的字符
symbol = symbolString[index]
# 如果当前字符属于 左括号集 则入栈
if symbol in '([{':
s.push(symbol)
# 如果当前字符 不是左括号(那当前就是右括号)
else:
# 并且栈是空的
if s.isEmpty():
# 匹配标志设置为 False 表示匹配失败(孤零零的右括号)
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(left, right):
lefts = "([{"
rights = ")]}"
# 调用字符串的index方法,index() 方法查找指定值的首次出现,并返回索引。
# 左右索引对应,表明符号匹配
return lefts.index(left) == rights.index(right)
测试结果如下图所示:
以上两个例子说明,在处理编程语言的语法结构时,栈是十分重要的数据结构。几乎所有记法都有某种需要正确匹配和嵌套的符号。除此之外,栈在计算机科学中还有其他一些重要的应用场景,让我们继续探索。
来源:https://blog.csdn.net/jiang1126/article/details/123268956


猜你喜欢
- 本文实例讲述了PHP实现二维数组中的查找算法。分享给大家供大家参考,具体如下:方法1:silu从左下角最后一行的第一个元素开始,遍历。如果小
- 摘要:在本篇博客中,我们将介绍如何优化YOLOv5车牌识别系统的性能,以及如何将模型部署到实际应用中。我们将重点讨论模型压缩、加速技术和部署
- 在我们开始一个项目的设计的时候,脑子里肯定有无数的构想。是做视觉冲击强烈、夺人眼球的绚丽风格?还是复古的拼贴风?又或者目前最in的极简主义设
- 一、概念触发器是一种特殊类型的存储过程,不由用户直接调用。创建触发器时会对其进行定义,以便在对特定表或列作特定类型的数据修改时执行。触发器可
- 最好的方法: 先说一下基本的东西: <%@ codepage=65001%>UTF-8 <%@&nbs
- Index.asp:程序代码<html><head><meta http-equiv="Conten
- 年底,抽奖这个话题很多人都会讨论,都希望可以中奖。接下来我就使用 Python 中的 Tkinter 模块来实现一个简单的滚动抽奖器。一、T
- 该语言中缩进是其精髓,通过缩进可以表示函数、循环等程序结构的范围。有时写完程序后,发现所有程序需要放入函数def中,这时就需要对一整块程序同
- 在Flash播放器运行时,将不同来源的资源划分到独立的沙箱(sandbox)内,不同沙箱之间不能彼此操作数据(除非目标沙箱做过一些设置,授权
- 如果原来没有使用过正则表达式,那么可能对这个术语和概念会不太熟悉。不过,它们并不是您想象的那么新奇。请回想一下在硬盘上是如何查找文件的。您肯
- 前言判断文件是否存在在实际应用中用的非常多,下面我们来归纳一下检查文件、文件夹是否存在的各种操作一.检查文件夹/文件是否存在1. os.pa
- 说到聚集索引,我想每个码农都明白,但是也有很多像我这样的猥程序员,只能用死记硬背来解决这个问题,什么表中只能建一个聚集索引,然后又扯到了目录
- 1. 功能分析1.加载文件夹内所有的Excel数据;2.生产贡献度分析图表(以柱状图显示表格数据);3.提起Excel表格中指定列数据;4.
- asp 中处理文件上传以及删除时常用的自定义函数:删除文件,建立目录的程序,根据原文件名生成新的随机文件名,CMS替换函数,将所有开始,结束
- 本文为大家分享了python2.7+selenium2实现淘宝滑块自动认证的具体代码,供大家参考,具体内容如下1.编译环境 操作系统:win
- 在 TypeScript 中一共有 7 种基本类型。1、booleanvar isDone: boolean = false;2、numbe
- MySQL Shell import_table数据导入1. import_table介绍这一期我们介绍一款高效的数据导入工具,MySQL
- 操作系统:Windows2000,IIS5出现症状:使用ASPJPEG时执行Server.CreateObject("Persit
- 天冷,人懒,事多,我就不全文翻译了。只列几个标题,很多内容完全按照我自己的理解写了一下。想读原汁原味的请移步:Icon design tre
- 一、前言很多网站提供视频转GIF的功能,但要么收费要么有广告实际上我们通过python,几行代码就能够实现视频转gif二、教程1. 安装必备