小学四则运算“软件”之初版
作业要求地址:http://www.cnblogs.com/xiangxuer/p/9695909.html
github地址:https://github.com/1627851906/sizeyunsuan
1.个人软件过程耗时估计与统计表
PSP2.1 | Personal Software Process Stages | predicted(h) | actual(h) |
· Planning | 计划 | 1 | 1 |
· Estimate | 估计这个任务需要多少时间 | 8 | 10 |
· Development | 开发 | 7 | 7 |
· Analysis | 需求分析 (包括学习新技术) | 1 | 0.5 |
· Design Spec | 生成设计文档 | 1 | 1 |
· Design Review | 设计复审 | 1 | 2 |
· Coding Standard | 代码规范 | 1 | 1 |
· Design | 具体设计 | 1 | 2 |
· Coding | 具体编码 | 6 | 6 |
· Code Review | 代码复审 | 7 | 9 |
· Test | 测试(自我测试,修改代码,提交修改) | 1 | 0.5 |
· Reporting | 报告 | 1 | 1 |
· | 测试报告 | 0.5 | 0.5 |
· | 计算工作量 | 0.5 | 0.5 |
· | 并提出过程改进计划 | 0.5 | 0.5 |
2.构思
因为是用java写的,所以想到用已经存在的Stack类来存放操作数和操作符,定义了两个Stack,一个存放Float类型,一个存放Character类型,用户决定出题数,但是每道题的操作数是随机出的,在这里写死了生成操作符的数目1~N,后期可以修改,只不过不想生成太长的式子,操作数就是操作符数目加一,后面如果出现乘号或除号后面出现加号或者减号,则添加括号,括号也压进操作符栈。然后事先定义一个算术符优先级表,进入一个循环,每次比较栈顶和次栈顶两个操作符的优先级,有‘<’, '>', '=',然后进行压栈入栈操作,最后操作符栈只剩下一个等于号并且操作数栈只剩一个操作数,即为整个式子答案。
3.设计
3.1、算术符优先级表
private static char[] signArray = new char[]{'+', '-', '×', '÷','/', '(', ')', '='};
private static char[][] signPriority = new char[][]{{'>', '>', '<', '<', '<','<', '>','>'},
{'>', '>', '<', '<', '<', '<', '>','>'}, {'>', '>', '>', '>', '<', '<', '>','>'}, {'>', '>', '>', '>', '<', '<', '>','>'},
{'>','>','>','>','>','>','>','>'},{'<', '<', '<', '<', '<','<', '=','>'}, {'>', '>', '>', '>', '<', '>', '>','>'}, {'<', '<', '<', '<', '<', '<', '<','<'}};
3.2、计算式子答案方法
1 private static Float getResult(Stack<Float> operatedNumber, Stack<Character> operatedSign) { 2 int count = 0, flag=1; 3 Stack<Float> tempNumber = new Stack<Float>(); 4 Stack<Character> tempSign = new Stack<Character>(); 5 Float newData = null, numberTop = null, numberNext = null, numberNextNext = null; 6 Character signTop = null, signNext = null; 7 while (operatedNumber.size() > 1 && operatedSign.get(operatedSign.size() - 1) != '=') { 8 switch (signPriority[getPosition(operatedSign.get(operatedSign.size() - 1))][getPosition(operatedSign.get(operatedSign.size() - 2))]) { 9 case '>': 10 numberTop = operatedNumber.pop(); 11 numberNext = operatedNumber.pop(); 12 signTop = operatedSign.pop(); 13 newData = calculate(numberTop, signTop, numberNext); 14 operatedNumber.push(newData); 15 break; 16 case '<': 17 numberTop = operatedNumber.pop(); 18 numberNext = operatedNumber.pop(); 19 numberNextNext = operatedNumber.pop(); 20 signTop = operatedSign.pop(); 21 signNext = operatedSign.pop(); 22 if (!operatedSign.isEmpty()&& (signNext == '(' || operatedSign.get(operatedSign.size()-1)=='(')) { 23 if (operatedSign.get(operatedSign.size()-1)=='(') { 24 operatedSign.pop(); 25 operatedNumber.push(numberNextNext); 26 flag=0; 27 } 28 else { 29 operatedNumber.add(numberNextNext); 30 operatedNumber.add(numberNext); 31 } 32 while(operatedSign.get(operatedSign.size()-1)!=')') { 33 tempSign.add(operatedSign.pop()); 34 count++; 35 } 36 tempSign.push('='); 37 for (int i =0; i<count+1; i++) { 38 tempNumber.add(operatedNumber.pop()); 39 } 40 tempNumber = setNumberReserve(tempNumber); 41 tempSign = setSignReserve(tempSign); 42 if (flag==1) { 43 newData = calculate(numberTop, signTop, getResult(tempNumber,tempSign)); 44 operatedNumber.push(newData); 45 } 46 else { 47 newData = calculate(numberNext, signNext, getResult(tempNumber,tempSign)); 48 operatedNumber.push(newData); 49 operatedNumber.push(numberTop); 50 operatedSign.push(signTop); 51 } 52 } 53 else { 54 newData = calculate(numberNext, signNext, numberNextNext); 55 operatedSign.push(signTop); 56 operatedNumber.push(newData); 57 operatedNumber.push(numberTop); 58 } 59 break; 60 case '=': 61 operatedSign.pop(); 62 operatedSign.pop(); 63 break; 64 default: 65 break; 66 } 67 } 68 return operatedNumber.get(0); 69 }
3.2 处理用户输入答案方法
1 private static Float inputAnswer() { 2 String answer = null; 3 String pattern = "(\\d+)/(\\d+)"; 4 Scanner in = new Scanner(System.in); 5 boolean isVaild = false; 6 while (!isVaild) { 7 try { 8 answer = in.nextLine(); 9 isVaild = true; 10 Pattern p = Pattern.compile(pattern); 11 Matcher matcher = p.matcher(answer); 12 if (matcher.find()) { 13 return Float.parseFloat(matcher.group(1)) / Float.parseFloat(matcher.group(2)); 14 } 15 else { 16 return Float.parseFloat(answer); 17 } 18 } 19 catch (Exception e) { 20 System.out.println("输入错误!请重新输入"); 21 in.nextLine(); 22 } 23 } 24 return Float.parseFloat("0"); 25 }
4.运行效果
5.遇到的问题
1.某些式子算出的答案会出现负数,不符合题目要求;
解决方法;1.重新生成一个不是负数的式子,方法不太好,但是比较简单。2.避免减法出现的负数,但是由于是先生成式子,在进行计算,有一些比较长的式子,如100÷50+3-2等之类的的式子,避免负数的出现比较麻烦,因为负数不是直接因为3-2生成的,所以我最后选择了重新生成一个答案不是负数的式子。
2.计算结果的答案不正确;
入栈出栈没设计好,逻辑不够清晰,经过代码调试,解决问题。
3.生成分数的控制
生成分数途中可能出现假分数,所以先记录下分母的值,控制分子在生成时比分母小的范围内随机生成。生成分数约分问题,因为想不到好的方法,有待解决。