问题描述:括号的使用必须遵循 “平衡”规则,即
首先,每个开括号要恰好对应一个闭括号;
其次,每对开闭括号要正确的嵌套
正确的括号:(()()()()),(((()))),
(()((())()))
错误的括号:((((((()),())),(()()(()
对括号是否正确匹配的识别,是很多语言编译器的基础算法
解题思路:从左到右扫描括号串,最新打开的左括号,应该匹配最先遇到的右括号
这样,第一个左括号(最早打开),就应该匹配
最后一个右括号(最后遇到)
这种次序反转的识别,正好符合栈的特性
步骤:
1.创造一个空栈
2.若为左括号,则加入栈顶;若为右括号,则判断栈是否为空,若空,则无与右括号匹配的左括号,匹配失败,反之,则与栈顶的左括号匹配,将栈顶的左括号pop。(实现最新打开的左括号,应该匹配最先遇到的右括号)
3.当括号串为空时,判断栈是否为空,若空,则匹配成功,反之,匹配失败。
demo:
from stack import Stack
#Stack是自定义栈类
def ParChecker(symbolstr):
s = Stack()
s_list = list(symbolstr)
print(len(s_list))
last = 0
for string in s_list:
last += 1
print(last)
if string == '(':
s.push(string)
print('(')
elif string == ')':
print(')')
if s.isEmpty():
print('error1')
return False
else:
s.pop()
if last == len(s_list):
if s.isEmpty():
return True
else:
print('error2')
return False
print(ParChecker('((())'))
通用括号匹配
from stack import Stack
#Stack是自定义栈类
def ParChecker(symbolstr):
s = Stack()
s_list = list(symbolstr)
opens = '([{'
closers = ')]}'
last = 0
for string in s_list:
last += 1
if string in opens:
s.push(string)
elif string in closers:
if s.isEmpty():
print('error1')
return False
else:
#当右括号类型与栈顶括号类型相同时,移除栈顶
top = s.pop()
if closers.index(string) != opens.index(top):
return False
if last == len(s_list):
if s.isEmpty():
return True
else:
print('error2')
return False
print(ParChecker('(([]))}'))
问题描述:
所谓的“进制”
,就是用多少个字符来表
示整数
十进制是0~9这十个数字字符,二进制是0、1两
个字符
我们经常需要将整数在二进制和十进制之间转换
十进制转换为二进制,采用的是“除以2
求余数”的算法
将整数不断除以2,每次得到的余数就是由低到
高的二进制位
“除以2”的过程,得到的余数是从低到高的次序,而输出则是从高到低,所以需要一个栈来反转次序
思路:
将十进制整数除以2,若余数不为0,则压入栈顶;得到的栈再取出得到二进制
demo:
from stack import Stack
#Stack是自定义栈类
def tenTotwo(num):
s = Stack()
while num != 0:
#转换为二进制,故除以2
s.push(num % 2)
num = num // 2
string = ''
while not s.isEmpty():
string = string + str(s.pop())
print(s.items)
return string
print(tenTotwo(33))
转换成其他进制,只需改变除数即可
问题描述:
中缀表达式
BC,这种操作符(operator)介于操作数(
operand)中间的表示法,称为“中缀”表示法
但有时候中缀表示法会引起混淆,如
“A+BC”
是A+B然后再乘以C
还是BC然后再去加A?
前缀、中缀和后缀表达式
❖再来看中缀表达式“(A+B)C”
,按照转换的规则,前缀表达式是“+ABC”,而后缀表达式是“AB+C”
前缀和后缀表达式
❖例如中缀表达式A+B
将操作符移到前面,变为“+AB”
或者将操作符移到最后,变为“AB+”
❖我们就得到了表达式的另外两种表示法:
“前缀”和“后缀”表示法
以操作符相对于操作数的位置来定义
❖在中缀表达式里必须
的括号,在前缀和后缀表达式中消失了?
❖在前缀和后缀表达式中,操作符的次序完
全决定了运算的次序,不再有混淆
所以在很多情况下,表达式的计算机表示都避免
用复杂的中缀形式
解决思路:
中缀表达式转换为前缀和后缀形式
无论表达式多复杂,需要转换成前缀或者后缀,只需要两个步骤;将中缀表达式转换为全括号形式
将所有的操作符移动到子表达式所在的左括号(前缀)或者右括号(后缀)处,替代之,再删除所有的括号
流程:
前提限制:后面的算法描述中,约定中缀表达式是由
空格隔开的一系列单词(token)构成,
操作符单词包括/±()
而操作数单词则是单字母标识符A、B、C等。*
❖首先,创建空栈opstack用于暂存操作符
,空表postfixList用于保存后缀表达式
❖将中缀表达式转换为单词(token)列表
从左到右扫描中缀表达式单词列表
如果单词是操作数,则直接添加到后缀表达式列表的
末尾
如果单词是左括号“(”,则压入opstack栈顶
如果单词是右括号“)”,则反复弹出opstack栈顶操作符,加入到输出列表末尾,直到碰到左括号
如果单词是操作符“*/±”,则压入opstack栈顶
• 但在压入之前,要比较其与栈顶操作符的优先级
• 如果栈顶的高于或等于它,就要反复弹出栈顶操作符,加入到输出列表末尾
• 直到栈顶的操作符优先级低于它
❖中缀表达式单词列表扫描结束后,把opstack栈中的所有剩余操作符依次弹出,添加到输出列表末尾
❖把输出列表再用join方法合并成后缀表达式字符串,算法结束
总结:
在从左到右扫描逐个字符扫描中缀表达式的过程中,采用一个栈来暂存未处理的操作符
栈顶的操作符就是最近暂存进去的,当遇到一个新的操作符,就需要跟栈顶的操作符比较下优先级,再行处理
from stack import Stack
def infixToPostfix(string):
opstack = Stack()
postfixlist = []
token = string.split(' ')
prec = {
'*':3, '/':3, '+':2, '-':2, '(':1
}
for astr in token:
if astr in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789':
postfixlist.append(astr)
elif astr == '(':
opstack.push(astr)
elif astr == ')':
while opstack.peek() != '(':
postfixlist.append(opstack.pop())
else:
opstack.pop()
elif astr in '*/+-':
if not opstack.isEmpty():
#要考虑栈是否为空,不然索引会出错
while prec[astr] <= prec[opstack.peek()]:
postfixlist.append(opstack.pop())
else:
opstack.push(astr)
else:
opstack.push(astr)
while not opstack.isEmpty():
#要考虑栈不为空,则一直出栈
postfixlist.append(opstack.pop())
return ' '.join(postfixlist)
print(infixToPostfix('( ( A - B ) * B )'))
初看算法不能完全理解,就按照流程编程,非常有助于理解
问题描述:
在对后缀表达式从左到右扫描的过程中,
❖由于操作符在操作数的后面,
❖所以要暂存操作数,在碰到操作符的时候
,再将暂存的两个操作数进行实际的计算
仍然是栈的特性:操作符只作用于离它最近的两
个操作数
思路:
我们弹出两个操作数,计算得到结果30
需要注意:
先弹出的是右操作数
后弹出的是左操作数,这个对于-/很重要!
❖为了继续后续的计算,需要把这个中间结
果30压入栈顶
❖继续扫描后面的符号
❖当所有操作符都处理完毕,栈中只留下1
个操作数,就是表达式的值
demo:
from stack import Stack
def postfixeval(fixString):
#表达式的符号间隔一个空格
fix_list = fixString.split(' ')
opstack = Stack()
for string in fix_list:
if string in '0123456789':
#要求操作数是个位数,待改进
opstack.push(string)
elif string in '*/+-':
s = opstack.pop()
e = eval(opstack.pop() + string + s)
#要保持数据项为string类型
opstack.push(str(e))
return opstack.pop
print('3 2 2 * -')