五人作业
功能:
程序主要功能,是可以输入一个运算表达式,然后输出相对应的表达式的计算值。
例如,我们输入的参数值为:1+2*3-4+6,那么它将把每一步运算的优先级,以及运算过程进行列举,并且最终算出最后的表达式的值。
思路:
采用栈,模拟数学运算来完成。
用一个字符列表(exp)来存储数学表达式,定义一个变量index表示exp的下标,下标从0开始。首先定义两个栈,stackOfOperator和stackOfNum,分别存储运算符和运算数,遇到运算数直接放进stackOfNum,遇到运算符,分四种情况:
(1)遇到负号;
(2)遇到右括号;
(3)遇到左括号;
(4)遇到+-*/;
前三种情况容易理解,第四种情况中四则运算是遵循先乘除再加减的(例如2*3+1),因此对于每个运算符,都要和stackOfOperator的栈顶符号等级比较,如果这个符号的等级比stackOfOperator栈顶符号等级高,什么也不做,直接放进栈;如果小于等于,就需要把stackOfNum的栈顶两个数字抽出来,进行计算。这里有个问题,在如果第一个运算符时,此时stackOfOperator为空,而且又需要与stackOfOperator栈顶运算符比较等级,为了解决这个问题,我在初始化stackOfOperator的时候,放进一个#,设置其等级为最低,用代码表示即为:
stackOfOperator, stackOfNum = ['#'], []
方法:
(1):delBlank, 用于删除字符串内的空格
(2):Precede方法,用来比较两个操作符的优先级,就是看那个操作符优先级高,从而来判定是否弹栈
(3):Operate方法,是根据传入的两个值的参数,以及操作符,来进行加减乘除等操作,从而计算出表达式的值
(4):Calc方法,是采用前面所述的算法,利用栈来模拟整个操作的过程,通过优先级的函数,来分布计算出每一步的计算值,并且输出到屏幕中
(5):Main方法,是整个程序的入口方法,它从命令行参数中获取表达式的值,并且调用前面叙述的其他方法,得到最终的计算值并且print到屏幕。
代码如下:
def delBlank(s):
from re import sub
return sub(r'\s+', '', s)
def precede(a, b):
# 优先级表格
prior = (
#'+' '-' '*' '/' '(' ')' '#'
('>', '>', '<', '<', '<', '>', '>'), # '+'
('>', '>', '<', '<', '<', '>', '>'), # '-'
('>', '>', '>', '>', '<', '>', '>'), # '*'
('>', '>', '>', '>', '<', '>', '>'), # '/'
('<', '<', '<', '<', '<', '=', ' '), # '('
('>', '>', '>', '>', ' ', '>', '>'), # ')'
('<', '<', '<', '<', '<', ' ', '=') # '#'
)
# 运算符
char2num = {
'+': 0,
'-': 1,
'*': 2,
'÷': 3,
'(': 4,
')': 5,
'#': 6
}
return prior[char2num[a]][char2num[b]]
def operate(a, b, operator):
'进行运算'
if operator == '+':
return a + b
elif operator == '-':
return a - b
elif operator == '*':
return a * b
elif operator == '÷':
if b == 0:
return "VALUE ERROR" # 除以0
else:
return a / b
def calc(exp):
retval = []
exp += '#'
operSet = "+-*÷()#"
stackOfOperator, stackOfNum = ['#'], []
steps = []
pos, ans, index, length = 0, 0, 0, len(exp)
while index < length: # 逐个字符读取
e = exp[index]
if e in operSet:
# 是运算符号,处理
topOperator = stackOfOperator.pop()
compare = precede(topOperator, e)
if compare == '>':
try:
b = stackOfNum.pop()
a = stackOfNum.pop()
except:
return "FORMAT ERROR"
ans = operate(a, b, topOperator)
steps.append(str(a) + topOperator + str(b) + '=' + str(ans))
if ans == "VALUE ERROR":
return steps
else:
stackOfNum.append(ans)
elif compare == '<':
stackOfOperator.append(topOperator)
stackOfOperator.append(e)
index += 1
elif compare == '=':
index += 1
else:
# 取下一个数字
pos = index
while not exp[index] in operSet:
index += 1
temp = exp[pos:index] # 数字(字符串型)
stackOfNum.append(Fraction(temp)) # 数字(分数型)
if len(stackOfNum) == 1 and stackOfOperator == []:
ans = stackOfNum.pop()
steps.append(str(ans))
else:
ans = "INPUT ERROR"
steps.append(str(ans))
return steps
效果图:
总结:
在本次代码的编写过程中我发现,有时候你一个东西写完之后,如果你一开始并没有一个清晰的逻辑,把其中一个很小的问题忽视了,你将在最后检查的时候花费大量的时间去找这个小问题,一般这个问题都是你觉得肯定是这样的,是出乎意料的,没有太在意地方,这样话,你在检查的时候回很难找,花费大量的时间。
这次代码编写虽然基本功能实现了,但是我感觉,还存在改进的地方,尤其是用户体验的地方,虽然我显示了解答的过程,但是却不是特别的清晰,针对低年级的用户可能还是不太能够使其理解整个解答的过程。这一方面还需改进。

浙公网安备 33010602011771号