1.
PSP
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
10 |
10 |
· Estimate |
· 估计这个任务需要多少时间 |
10 |
10 |
Development |
开发 |
655 |
600 |
· Analysis |
· 需求分析 (包括学习新技术) |
30 |
35 |
· Design Spec |
· 生成设计文档 |
30 |
40 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
10 |
15 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
5 |
5 |
· Design |
· 具体设计 |
40 |
70 |
· Coding |
· 具体编码 |
5h*60 |
8h*60 |
· Code Review |
· 代码复审 |
1h*60 |
2h*60 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
3h*60 |
2h*60 |
Reporting |
报告 |
290 |
60 |
· Test Report |
· 测试报告+博客 |
4h*60 |
3h*60 |
· Size Measurement |
· 计算工作量 |
10 |
10 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
40 |
30 |
合计 |
|
955 |
1785 |
2.项目要求
- 能自动生成小学四则运算题目
- 除了整数以外,还要支持真分数的四则运算
-
解题思路
- 了解四则运算的大概思路,即:生成四则运算式子;用户输入结果;程序检验用户输入的结果是否正确;若用户输入的结果错误,即把正确答案输入。
- 用数组和随机函数随机生成四则运算式子;
- 了解逆波兰式,即将中缀表示式转换成后缀表达式,以便计算机对式子进行运算;
- 检验结果并输出;
设计实现及代码说明
1、NiBoLanShi.java
对四则运算式子从中缀表达式转换成后缀表达式,以便计算机计算。
-
1 package sizeyunsuan; 2 3 import java.util.List; 4 import java.math.BigDecimal; 5 import java.util.ArrayList; 6 import java.util.Stack; 7 8 public class NiBoLanShi { 9 public static String cal(String str) { 10 //对表达式进行预处理,并简单验证是否是正确的表达式 11 //存放处理后的表达式 12 List<String> list = new ArrayList<>(); 13 char[] arr = str.toCharArray(); 14 15 //存放数字临时变量 16 StringBuffer tmpStr = new StringBuffer(); 17 for (char c : arr) { 18 //如果是数字或小数点,添加到临时变量中 19 if (c>='0' && c<='9') { 20 tmpStr.append(c); 21 }else if(c=='.') { 22 if(tmpStr.indexOf(".")>0) { 23 throw new RuntimeException("非法字符"); 24 } 25 tmpStr.append(c); 26 } 27 28 //如果是加减乘除或者括号,将数字临时变量和运算符依次放入List中 29 else if (c=='+' || c=='-' || c=='*' || c=='/' || c=='(' || c==')') { 30 if (tmpStr.length() > 0) { 31 list.add(tmpStr.toString()); 32 tmpStr.setLength(0); 33 } 34 list.add(c + ""); 35 } 36 else if (c==' ') { 37 continue; 38 } 39 else { 40 throw new RuntimeException("非法字符"); 41 } 42 } 43 if (tmpStr.length() > 0) { 44 list.add(tmpStr.toString()); 45 } 46 47 //初始化后缀表达式 48 List<String> strList = new ArrayList<>(); 49 50 //运算过程中,使用了两次栈结构, 51 //第一次是将中缀表达式转换成后缀表达式,第二次是计算后缀表达式的值 52 Stack<String> stack = new Stack<>(); 53 54 //声明临时变量,存放栈元素 55 String tmp; 56 57 //将中缀表达式转换成后缀表达式 58 for (String s : list) { 59 //如果是左括号直接入栈 60 if (s.equals("(")) { 61 stack.push(s); 62 } 63 64 //如果是右括号,执行出栈操作,依次添加到后缀表达式中,直到出栈元素为左括号,左括号和右括号都不添加到后缀表达式中 65 else if (s.equals(")")) { 66 while (!(tmp = stack.pop()).equals("(")) { 67 strList.add(tmp); 68 } 69 } 70 71 //如果是加减乘除,弹出所遇优先级大于或等于该运算符的栈顶元素(栈中肯定没有右括号,认为左括号的优先级最低),然后将该运算符入栈 72 else if (s.equals("*") || s.equals("/")) { 73 while(!stack.isEmpty()) { 74 //取出栈顶元素 75 tmp = stack.peek();//取出但不移除 76 if (tmp.equals("*") || tmp.equals("/")) { 77 stack.pop(); 78 strList.add(tmp); 79 } 80 else { 81 break; 82 } 83 } 84 stack.push(s); 85 } 86 else if (s.equals("+") || s.equals("-")) { 87 while(!stack.isEmpty()) { 88 //取出栈顶元素 89 tmp = stack.peek(); 90 if (!tmp.equals("(")) { 91 stack.pop(); 92 strList.add(tmp); 93 } 94 else { 95 break; 96 } 97 } 98 stack.push(s); 99 } 100 101 //如果是数字,直接添加到后缀表达式中 102 else { 103 strList.add(s); 104 } 105 } 106 107 //最后依次出栈,放入后缀表达式中 108 while (!stack.isEmpty()) { 109 strList.add(stack.pop()); 110 } 111 112 //计算后缀表达式的值 113 Stack<BigDecimal> newStack = new Stack<>(); 114 for (String s : strList) { 115 //若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的放到运算符的左边 116 //运算后的结果再进栈,直到后缀表达式遍历完毕 117 if (s.equals("*") || s.equals("/") || s.equals("+") || s.equals("-")) { 118 BigDecimal b1 = newStack.pop(); 119 BigDecimal b2 = newStack.pop(); 120 switch (s) { 121 case "+": 122 newStack.push(b2.add(b1)); 123 break; 124 case "-": 125 newStack.push(b2.subtract(b1)); 126 break; 127 case "*": 128 newStack.push(b2.multiply(b1)); 129 break; 130 case "/": 131 newStack.push(b2.divide(b1, 9, BigDecimal.ROUND_HALF_UP)); 132 break; 133 } 134 } 135 136 //如果是数字,入栈 137 else { 138 newStack.push(new BigDecimal(s)); 139 } 140 } 141 142 //最后,栈中仅有一个元素,就是计算结果 143 return newStack.peek().toString(); 144 } 145 }
2、CreateRandom.java
利用代码随机产生四则运算表达式。
-
1 package sizeyunsuan; 2 3 4 public class CreateRandom { 5 public void create(int m, int n, String[] fuHao, String[] strArray) { 6 String str = ""; 7 8 //随机生成式子 9 for (int i = 0; i < n; i++) { 10 str = ""; 11 int[] arr1 = new int[n]; 12 int[] arr2 = new int[n]; 13 arr2[i] = (int)(Math.random()*m+1); 14 for(int j = 0; j < n; j++) { 15 int order = (int)(Math.random()*4); 16 arr1[j] = (int)(Math.random()*m+1); 17 str = str + arr1[j] + fuHao[order]; 18 } 19 str = str + arr2[i]; 20 strArray[i] = str; 21 System.out.println("第"+(i+1)+"题:"+str); 22 arr1 = null; 23 arr2 = null; 24 } 25 System.out.println("\n"); 26 } 27 }
3、Student.java
主类,用户输入答案,检验其答案是否正确。
-
1 package sizeyunsuan; 2 3 import java.util.Scanner; 4 5 6 9 public class Student { 10 11 public static void main(String[] args) { 12 CreateRandom createRandom = new CreateRandom(); 13 NiBoLanShi niBoLanShi = new NiBoLanShi(); 14 String[] fuHao = {"+","-","*","/"}; 15 Scanner input = new Scanner(System.in); 16 System.out.println("请输入范围内的计算:"); 17 int m = input.nextInt(); 18 System.out.println("请输入要产生的题数:"); 19 int n = input.nextInt(); 20 String[] strArray = new String[n]; 21 System.out.println("\n题目\n"); 22 createShiZi.create(m, n, fuHao, strArray); 23 for(int i = 0; i<n; i++) { 24 String result = niBoLanShi.cal(strArray[i]); 25 System.out.println("第"+(i+1)+"题:"+strArray[i]); 26 System.out.print("你的答案:"); 27 String yourAnswer = input.next(); 28 if (yourAnswer.equals(result)) { 29 System.out.println("True\n"); 30 }else { 31 System.out.println("False"); 32 System.out.println("正确答案:"+result+"\n"); 33 } 34 } 35 } 36 }
-
测试运行
为了方便展示,测试以小数目为主:
-
总结
这次的用Java实现简单的四则运算,让我重拾了以前的基础知识,譬如数组,列表等等。程序看起来比较的简陋,本来是想结合墨刀的原型进行融合的,奈何能力有限,希望在后续的学习中不断充实自己,然后能完成这一目标,设计一个精美的小学生四则运算软件,有机会的话在石墨文档等互联网平台进行发布。