数据结构与算法Python版p15-p20
一、创建Stack类p15
1.1右边是栈顶
# 右边是栈顶
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 size(self):#栈长度
return len(self.items)
def peek(self):
if self.isEmpty():
print('空栈')
else:
return self.items[len(self.items) - 1]
# 测试代码
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())
输出
True
dog
3
False
8.4
True
2
1.2左边是栈顶
# # 左边是栈顶
# 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 size(self):
# return len(self.items)
# # 返回栈顶元素,最左边
# def peek(self):
# if self.isEmpty():
# print('空栈')
# else:
# return self.items[0]
二、通用括号匹配p16
# 通用括号匹配()[]{}
def parChecker(string):
left = list('([{')
right = list(')]}')
# 初始化一个栈
s = Stack()
for i in list(string):
if i in left:#所有左括号全部push进栈
s.push(i)
else:
if s.isEmpty():
# 如果是右括号,而且栈是空的,字符串一定是错的
return False
elif left.index(s.peek()) == right.index(i):
# 判断栈顶元素和当前元素是否匹配,匹配就出栈,继续循环匹配
s.pop()
else:
return False
return True
# 测试
print(parChecker('{{([][])}()}'))
print(parChecker('{{([])}()}'))
print(parChecker('{{([][)}()}'))
print(parChecker(''))
print(parChecker('[}'))
输出
True
True
False
True
False
三、十进制转换为十六以下任意进制p17
# 十进制转换为十六以下任意进制
def baseConverter(number,base):
digits = '0123456789ABCDEF'
s = Stack()
if number == 0:
return '0'
while number > 0:
# a/2是2进制最后一位,商再除2,倒数第二位,依次进栈
s.push(number % base)
number = number // base
result = ''
# 翻转过来
for i in range(s.size()):
result = result + digits[s.pop()]
return result
# 测试
print(baseConverter(0,16))
print(baseConverter(233,16))
输出
0
E9
四、表达式转换p18-p19
4.1全括号中缀转后缀
由于是全括号表达式,每一个运算符对应一个括号,那么只需要将运算符移到相应括号的右括号的前面就可以了,最后再删掉所有括号即可。如:
((2+3)/(5*6))
⇒
\quad\Rightarrow\quad
⇒ ((2 3 +) (5 6 *)/)
⇒
\quad\Rightarrow\quad
⇒ 2 3 + 5 6 + /
def convert(string):
s = Stack()
result = []
raw_data = string.split()
# 遇到运算符,将运算符压入栈s中,其余全部保留
for i in raw_data:
if i in '+-*/':
s.push(i)
elif i == ')':
# 当遇到右括号把栈顶元素放下,并保留右括号
result.append(s.pop())
result.append(')')
else:
result.append(i)
# 去掉括号
result = [i for i in result if i not in '()']
result = ' '.join(result)
return result
4.2通用的中缀转后缀
这个比较麻烦,主要是运算符有优先级,而且还有括号,比如(A+B)
×
\times
×C的后缀为AB+C
×
\times
×,A+B
×
\times
×C的后缀为ABC
×
\times
×+,思路仍然是初始化一个栈和一个列表,栈用于存储运算符,列表为返回值,依次从左往右读取,记录运算符,只不过需要在合适的时候pop。为什么这个要用栈这个数据结构,是因为对于最简单的情形即全加全减,是从左往右的只需要push进栈里,遇到下一个在pop,这样push,pop,push,pop······,对于加法在前面,乘法在后面,我们反而需要先乘后加,反映在后缀表达式上就是乘法那个符号在加法那个符号的前面,但是读取的时候是先读到加法,再乘法,所以先进的后出,符合栈的特性。
def major(operator1,operator2):
major_dict = {'*':2,'/':2,'+':1,'-':1}
if major_dict[operator2] > major_dict[operator1]:
return True
else:
return False
def infixToPostfix(infixexpr):
s = Stack()
result = []
raw_data = infixexpr.split()
for i in raw_data:
if i == '(':
s.push(i)
elif i == ')':
# 遇到右括号,运算符出栈跟在结果后面,直到栈顶是左括号,这时候就匹配了,把左括号扔掉
while s.peek() != '(':
result.append(s.pop())
s.pop()
elif i in '+-*/':
if s.size() == 0:
s.push(i)
elif s.peek() == '(':
s.push(i)
# 遇到运算符判断一下,优先级大于栈顶的优先级,也push进去,小于等于出栈跟在结果后面,同时当前元素入栈,上面两个是特殊情况,要一开始push运算符进去,不需要比较
elif major(s.peek(),i):
s.push(i)
else:
result.append(s.pop())
s.push(i)
else:
result.append(i)
# 注意循环完之后,栈里面可能还有运算符,要全部出来,如5+2,循环完是5 2,栈里面还有一个+
while (not s.isEmpty()):
result.append(s.pop())
result = ' '.join(result)
return result
五、后缀表达式求值p20
def doMath(op,op1,op2):
# 定义计算函数,op是运算符,op1,op2是操作的两个数
if op == '*':
return op1 * op2
elif op == '/':
return op1 / op2
elif op == '-':
return op1 - op2
else :
return op1 + op2
def postfixEval(string):
# 初始化一个栈,存入操作数
s = Stack()
raw_data = string.split()
for i in raw_data:
if i in '+-*/':
# 遇到运算符,将栈里最近的两个数pop出来做运算,并将结果push进栈里,继续向后读取操作数
num2 = int(s.pop())
num1 = int(s.pop())
s.push(doMath(i,num1,num2))
else:
s.push(i)
return s.items[0]
# 测试
print(postfixEval('10 2 5 * /'))
```!
输出
```python
1.0