2017282110261-高级软件工程第二次作业
1.项目Github地址
2.预估耗时
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | |
· Estimate | · 估计这个任务需要多少时间 | 10 | |
Development | 开发 | 340 | |
· Analysis | · 需求分析 (包括学习新技术) | 30 | |
· Design Spec | · 生成设计文档 | 30 | |
· Design Review | · 设计复审 (和同事审核设计文档) | 0 | |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | |
· Design | · 具体设计 | 30 | |
· Coding | · 具体编码 | 120 | |
· Code Review | · 代码复审 | 60 | |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | |
Reporting | 报告 | 180 | |
· Test Report | · 测试报告 | 150 | |
· Size Measurement | · 计算工作量 | 10 | |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | |
合计 | 530 |
3.解题思路
这个问题我之前学C#的时候在练习题上遇到过,由于当时已经把数据结构忘的一干二净,所以写了很复杂的if也解决不了这个问题,压根没想到这个题需要用到算法。去年考研的时候,数据结构里面又遇到了这个问题,不过这一次遇到我就掌握了解这个题的方法————逆波兰算法。说白了就是从计算机的角度来看我们平时看的中缀表达式很费劲,所以需要把中缀表达式转换成后缀表达式。这个过程需要用到栈这种数据结构。考虑到我现在主要使用Python所以这个题我就用pyhon来写了。然后就遇到了一个问题,如何加上命令行参数,这个我看网上都是用getopt模块,但是……这个模块的文档比较反人类,我看了好半天才看懂。。。。不过功能还是蛮强大的。
4.设计实现过程
就算掌握了逆波兰算法要把它实现出来还是挺麻烦的,麻烦在于表达式是由str和int组成的,所以要不停的在这两种数据类型之间转换,我承认我功力不够写出来的代码太丑,并且复杂的功能(带括号,不定操作符个数)我实现不出来……
整个程序,先随机生成运算符和操作数,这个比较简单。但是我为了后面转换表达式的模块能区分操作数和运算符,我让操作数为int类型。而在cmd上打印输出的表达式不管是运算符还是操作数都是字符类型。然后进行表达式的转化,这里就需要逆波兰算法了。我的办法是就是遍历表达式,挑出数字和运算符然后运算符按照算法思想入栈出栈,接着新生成一个列表存放转换结果。转换成功之后就开始计算后缀表达式的值。
5.代码说明
代码主要模块是backExp()函数和JudegeLevel()这两个函数,一个负责转换表达式,一个复杂判断运算符优先级,因为运算符都是字符类型且计算机无法自动判断优先级,所以比较麻烦要人为制定规则来判断优先级。
backExp()函数如下:
def backExp(exp1):
stack = [] #存放运算符的栈
bck = [] #存放后缀表达式
for i in range(len(exp1)):
if type(exp1[i]) == int:
bck.append(exp1[i])
if type(exp1[i]) == str:
if stack:
if judgeLevel(exp1[i], stack[-1]):
stack.append(exp1[i])
else:
bck.append(stack[-1])
stack.pop()
if stack and not judgeLevel(exp1[i], stack[-1]):
bck.append(stack[-1])
stack.pop()
stack.append(exp1[i])
else:
stack.append(exp1[i])
if stack:
stack = stack[::-1]
bck.extend(stack)
return bck
由于我只实现了3个运算符的表达式的计算所以代码比较粗暴,没有考虑更多运算符的情况。一上来就直接遍历表达式,遇到数字就直接追加到bak这个列表里面,遇到字符(操作符)就先判断存放操作符的栈是否为空,若为空则直接追加到栈中,不为空则判断此运算符和栈中已有运算符的优先级,然后进行出栈或者入栈的操作。等表达式遍历完之后我们的后缀表达式就转换完毕了。
JudgeLevel()函数如下:
def judgeLevel(op1, op2):
if op1 == 'x' and op2 == '+':
return True
if op1 == 'x' and op2 == '-':
return True
if op1 == '/' and op2 == '+':
return True
if op1 == '/' and op2 == '-':
return True
return False
这块的代码我写的也比较丑,直接4个if来判断优先级,这里我的想法是,只考虑op1的优先级比op2高的情况毕竟只有这4种情况,剩下的所有情况都是优先级低。
6.运行结果
这里我把后缀表达式也输出来了,结果也是能用分数表示。这里我没有自己算答案,但是稍微验证下程序给出的答案就知道结果没错。
7.实际花费时间
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 10 |
· Estimate | · 估计这个任务需要多少时间 | 10 | 10 |
Development | 开发 | 340 | 500 |
· Analysis | · 需求分析 (包括学习新技术) | 30 | 40 |
· Design Spec | · 生成设计文档 | 30 | 30 |
· Design Review | · 设计复审 (和同事审核设计文档) | 0 | 0 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 10 |
· Design | · 具体设计 | 30 | 40 |
· Coding | · 具体编码 | 120 | 180 |
· Code Review | · 代码复审 | 60 | 70 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 60 |
Reporting | 报告 | 180 | 150 |
· Test Report | · 测试报告 | 150 | 180 |
· Size Measurement | · 计算工作量 | 10 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 30 |
合计 | 530 | 660 |
8.项目小结
这次作业让我意识到了一个算法就算思想懂了,想要实现出来也是不容易的。对语言的熟悉程度决定了编码的时间,期间确实浪费了很多时间在解决小问题上了,比如列表逆序啊,cmd中文乱码啊之类的。细节决定成败,如果真的做的很粗糙的话功能上也没啥问题但是这样就失去了写作业的意义。这次暴露出来的问题还是代码功力不够,一些操作写的比较丑……我会继续加油的!
PS:1.如果图片看不到的话请使用chrome浏览器或Edge浏览器