此作业要求参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/7631
git地址:https://e.coding.net/sxl357/f4.git
功能一:
做这个题的时候开始完全没有思路,如何让程序计算一个表达式,我们通过查阅资料,利用搜索引擎,发现如果输入一个表达式是无法算出结果的,需要先将中缀表达式转换为后缀表达式,然后将后缀表达式的结果计算出来。在这一部分我们花费了很多时间,先去了解了如何将中缀表达式转换为后缀表达式。
具体步骤:
需要一个存放操作符的栈op_stack,输出结果的列表output
步骤:
从左到右遍历表达式:
1. 若是数字,直接加入到output
2. 若是操作符,比较该操作符和op_stack中操作符的优先级,若优先级大于op_stack中的,则压入到op_stack中
否则,将op_stack中优先级大于或等于该操作符优先级的所有操作符加入到output中,然后压入op_stack中
3. 若是左括号,压入到op_stack中
4. 若是右括号,将op_stack中所有左括号前面的操作符加入到output中
重复上面的步骤
然后将这一理论知识转换为具体的python代码,具体如下:
def make_Expression(s): operations=[] result='' front={'+':1,'-':1,'*':2,'/':2,'(':0,')':3} for i in s: if i in ['+','-','*','/','(',')']:#判断是否是操作符 if i=='(':#遇到左括号,将其直接放入栈中 operations.append(i) elif i==')':#遇到右括号,持续将栈顶元素弹出并输出,直至遇到左括号 while (len(operations)>0 and operations[-1]!='(' ):#-1表示列表的最后一个元素,即栈顶 p=operations.pop() result+=p operations.pop()#左括号只弹出不输出 elif len(operations)==0:#栈空,直接入栈 operations.append(i) elif front[operations[-1]]>=front[i]:#判断栈顶元素和操作符的优先级别 while len(operations)>0 and front[operations[-1]]>=front[i]:#持续将栈顶元素弹出并输出,直至遇到低于或等于此操作符的优先级别 p=operations.pop() result+=p operations.append(i) else: operations.append(i) else: result+=i#若是数,直接输出 while len(operations)>0:#将栈中的所有元素依次弹出 p=operations.pop() result+=p return result#返回后缀表达式
转换为后缀表达式之后就可以计算值了:
具体步骤:
需要一个存放中间结果的栈num_stack
步骤:
从左到右遍历表达式:
1. 若是数字,压入到num_stack中
2. 若是操作符,取出num_stack中的前两个元素,第二个是表达式左边的操作数,计算表达式的值,将求值结果压入到num_stack中
def make_Value(s): lists=[] for i in s: if i in ['+','-','*','/']: b=float(lists.pop())#先弹出的是b,下个弹出的是a a=float(lists.pop()) c=0 if i=='+':#判断做哪则运算 c=a+b elif i=='-': c=a-b elif i=='*': c=a*b else: c=a/b lists.append(c)#得到的结果压入栈中 else: lists.append(i) return lists[0]
这部分最大的障碍就是如何自动生成20道题,我们思考了两天无果,找了师哥的代码进行了学习和理解,最终搞明白了原理,又自己进行了修改,最终自己敲了一遍进行了运行。
def expre(self):#在类里定义函数必须传入self,指的是类实例对象本身 exp = [] for j in range(0,7): #range(a)=[0,1,2,3,...,a-1] if j % 2 != 0:#通过模2,生成带3个运算符4个10以内数字的表达式 operators = ['+', '-', '*', '/'] exp.append(operators[randint(0, len(operators) - 1)]) #随机生成运算符 else: exp.append(str(randint(1, 9))) #随机生成操作数 is_need_brackets = randint(0, 1) # 判断是否要括号 if is_need_brackets:#添加括号 expression = ''.join(self.make_brackets(exp))#.join()将序列中的元素以指定的字符连接生成一个新的字符串 #加括号时,调用生成括号表达式的函数,得到一个带括号的运算式 else:#不添加括号 expression = ''.join(exp) return expression
运行截图:
功能二
生成括号表达式部分,我们选用了枚举的方法,对于四个操作数三个运算符,最多可以有两对括号,括号的排列方式有10种情况,我们是选择一一把它列举出来。
# 生成括号表达式 def make_brackets(self,exp):#传入由运算符和数字组成的列表 expression = [] # 可能有一对括号,也可能有两对括号,所以最多有11个位置可以添加括号 #经过枚举,共有10种可能的添加方式 # 0表示直接将运算符或数字传入生成式,1表示在生成式加入左括号,2表示在生成式加入右括号,-1表示不作任何处理 judge_position= [ [1, 0, 0, 0, 2, 0, 0, 0, 0, -1, -1], [1, 0, 0, 0, 0, 0, 2, 0, 0, -1, -1], [0, 0, 1, 0, 0, 0, 2, 0, 0, -1, -1], [0, 0, 1, 0, 0, 0, 0, 0, 2, -1, -1], [0, 0, 0, 0, 1, 0, 0, 0, 2, -1, -1], [1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 2], [1, 1, 0, 0, 0, 2, 0, 0, 2, 0, 0], [1, 0, 0, 1, 0, 0, 0, 2, 2, 0, 0], [0, 0, 1, 1, 0, 0, 0, 2, 0, 0, 2], [0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 2] ] position = randint(0,9) if exp: i = 0 for j in judge_position[position]:#调用上述列表 if j ==0: expression.append(exp[i]) if i < len(exp): i += 1 elif j ==1: expression.append('(') elif j ==2: expression.append(')') return expression
功能三
通过分析此题,生成表达式后发现首先要规范化输出
# 答案与题目横向对齐,使输出规范化,实现功能三 def normal(num): i = 0 while i < num: generate = Expression() expression = generate.expre() expression1 = make_Expression(expression) # 将中缀表达式转换为后缀表达式 result = make_Value(expression1) # 计算后缀表达式的值 expression=expression+"=" print('%-15s %-15s' % (expression, result)) # 规范输出格式 i += 1
然后需要通过命令行参数传入-c执行这一部分,且要求需要输入正整数
def main(argv): if '-c' in sys.argv: # 实现功能三 count=float(sys.argv[2]) # 获取生成题目的个数 if count >=1: normal(count) else: print("题目数量必须是正整数。") else: question()#实现功能一二
需要输入正整数方面功能实现:
功能三全部实现:
结论:
这是第一次的两人结对的合作,感觉两人合作确实会碰触思想的火花,对同一个问题能够收获多样化的思路和方法,也能看到我的小伙伴在问题上坚持不懈的毅力,学到了很多知识,收获最大的就是规范化了我的代码书写,之前的我不太严谨,通过这一个星期的共同学习努力,规范化了我自己,感谢我的小伙伴。
结对伙伴:宋晓丽
结对地点:星华公寓622宿舍