简介
近期看了学长的字节跳动面试,收益匪浅,特别是在其中对算法题的考查。因此,打算重新用Python实现几种数据结构,并且进行相关的应用。
栈
栈的定义,就不重复了。直接上代码
class Stack(object):
def __init__(self,limit=10):
self.stack = [] #存放元素
self.limit = limit #栈容量极限
def push(self,data): #进栈,将元素放在栈顶
#判断元素是否溢出
if len(self.stack) >= self.limit:
raise IndexError('超出栈容量极限!')
self.stack.append(data)
def pop(self):
#判断栈是否为空
if self.stack:
return self.stack.pop()
else:
raise IndexError('pop from an empty stack!')
def peek(self):#查看栈顶元素
if self.stack:
return self.stack[-1]#返回队列最后一个元素
def is_empty(self): #判断栈是否为空
return not bool(self.stack)
def size(self): #返回栈的大小
return len(self.stack)
计算器的实现
实现了栈类之后,将其应用在计算器上:
主要难点:
- 输入字符串,如何转换成数字(多位数,而非常规的个位数字)以及符号‘
- 中缀表达式转化成后缀
- 利用后缀进行计算
1.运算式分割
核心思想:通过判断是否为数字为标准,利用符号位的序号来进行判断数字位的长度。
# 运算式分割
sym_list = [] # 符号序列列表
n = 0 #数字位的长度
fist_n = 0 #首个数字的位置
for i in range(0, len(mul)):
if mul[i].isnumeric(): #如果是数字,则开始计算长度
n += 1
else: #非数字,则将本符号前的数字整个切分append入列表中
if fist_n != fist_n + n: #长度为0的情况
sym_list.append(mul[fist_n:fist_n + n]) #先添加指定长度的数字位
sym_list.append(mul[i]) #添加符号位
fist_n = i + 1 #重新开始标记数字的首位置
n = 0 #重新计算
if i == len(mul) - 1: #末尾,直接添加最后的数字
sym_list.append(mul[fist_n:fist_n + n])
2.逆波兰操作
规则
- 如果读入操作数,直接放入输出字符串
- 读入“+,-,*,/”等一般运算符,则放入辅助栈中,注意,放入的字符的优先级必须高于栈顶符号优先级。如:如待放入“-”,栈顶为“*”,则需要先将“*”pop,并且放入输出字符转,之后再push“-”入栈。反之,则直接push入栈。
- 如果字符串为“(”,则直接入栈,并且之后,无需考虑其优先级。
- 如果为“)",则直接pop出所有在”(“之后的字符串,并且依次放入输出字符串。“(”,")"不需要放入输出字符串
- 如果最后辅助栈中还有字符,则直接依次pop进输出字符串
# 逆波兰操作,中缀改后缀
after_list = [] # 后缀列表
for i, x in enumerate(sym_list):
if x.isnumeric():
after_list.append(x)
else:
if stack_sign.is_empty():
stack_sign.push(x)
else:
if x == '(':
stack_sign.push(x)
if x == ')':
while stack_sign.peek() != '(':
after_list.append(stack_sign.pop())
stack_sign.pop()
if x == '+' or x == '-':
while stack_sign.peek() == '*' or stack_sign.peek() == '/':
after_list.append(stack_sign.pop())
stack_sign.push(x)
if x == '*' or x == '/':
stack_sign.push(x)
while not stack_sign.is_empty():
after_list.append(stack_sign.pop())
3.后缀计算
规则
- 从输出字符串依次进行,如果为数字,则放入新的辅助栈
- 如果为运算符(不需要放入栈),则取出后两位数字(a,b),进行相关计算。得到新的数字c,并且放入栈中。依次进行
- 如果最后只剩下一个数字,则为答案。
#通过后缀表达式计算结果
for i, x in enumerate(after_list):
if x.isnumeric():
stack_acc.push(x)
else:
b = float(stack_acc.pop())
a = float(stack_acc.pop())
if x == "+":
c = a + b
if x == "-":
c = a - b
if x == "*":
c = a * b
if x == "/":
c = a / b
stack_acc.push(c)
print("ans = ",stack_acc.pop())
完整代码
#File name:栈类的实现,以及计算器的应用
#Author: Long Version: 1.0 Date:2020.9.29
#Description: 实现计算器的基本操作
import re
class Stack(object):
def __init__(self,limit=10):
self.stack = [] #存放元素
self.limit = limit #栈容量极限
def push(self,data): #进栈,将元素放在栈顶
#判断元素是否溢出
if len(self.stack) >= self.limit:
raise IndexError('超出栈容量极限!')
self.stack.append(data)
def pop(self):
#判断栈是否为空
if self.stack:
return self.stack.pop()
else:
raise IndexError('pop from an empty stack!')
def peek(self):#查看栈顶元素
if self.stack:
return self.stack[-1]#返回队列最后一个元素
def is_empty(self): #判断栈是否为空
return not bool(self.stack)
def size(self): #返回栈的大小
return len(self.stack)
def Mul_det():
# 运算符ascii码
# 使用栈实现运算符匹配
mul = input("请输入运算式").strip()
stack_sign = Stack(len(mul)) # 操作符栈
stack_num = Stack(len(mul)) # 操作栈
stack_acc = Stack(len(mul)) # 辅助栈
# 运算式分割
sym_list = [] # 符号序列列表
n = 0 #数字位的长度
fist_n = 0 #首个数字的位置
for i in range(0, len(mul)):
if mul[i].isnumeric(): #如果是数字,则开始计算长度
n += 1
else: #非数字,则将本符号前的数字整个切分append入列表中
if fist_n != fist_n + n: #长度为0的情况
sym_list.append(mul[fist_n:fist_n + n]) #先添加指定长度的数字位
sym_list.append(mul[i]) #添加符号位
fist_n = i + 1 #重新开始标记数字的首位置
n = 0 #重新计算
if i == len(mul) - 1: #末尾,直接添加最后的数字
sym_list.append(mul[fist_n:fist_n + n])
# 逆波兰操作,中缀改后缀
after_list = [] # 后缀列表
for i, x in enumerate(sym_list):
if x.isnumeric():
after_list.append(x)
else:
if stack_sign.is_empty():
stack_sign.push(x)
else:
if x == '(':
stack_sign.push(x)
if x == ')':
while stack_sign.peek() != '(':
after_list.append(stack_sign.pop())
stack_sign.pop()
if x == '+' or x == '-':
while stack_sign.peek() == '*' or stack_sign.peek() == '/':
after_list.append(stack_sign.pop())
stack_sign.push(x)
if x == '*' or x == '/':
stack_sign.push(x)
while not stack_sign.is_empty():
after_list.append(stack_sign.pop())
#通过后缀表达式计算结果
for i, x in enumerate(after_list):
if x.isnumeric():
stack_acc.push(x)
else:
b = float(stack_acc.pop())
a = float(stack_acc.pop())
if x == "+":
c = a + b
if x == "-":
c = a - b
if x == "*":
c = a * b
if x == "/":
c = a / b
stack_acc.push(c)
print("ans = ",stack_acc.pop())
if __name__ == '__main__':
Mul_det()
# sig = ['', '-', '*', '/', '(', ')']
# mul = re.split("\+|\-|\*|\/|\(|\)",mul)#需要转义字符