GitHub 項目地址
https://github.com/ben-qiu-zou/-
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 |
項目要求
- 能自動生成小學四則運算題目
- 除了整數以外,還要支持真分數的四則運算
解題思路
- 了解四則運算的大概思路,即:生成四則運算式子;用戶輸入結果;程序檢驗用戶輸入的結果是否正確;若用戶輸入的結果錯誤,即把正確答案輸入。
- 用數組和隨機函數隨機生成四則運算式子;
- 了解逆波蘭式,即將中綴表示式轉換成后綴表達式,以便計算機對式子進行運算;
- 檢驗結果並輸出;
設計實現及代碼說明
1、NiBoLanShi.java
對四則運算式子從中綴表達式轉換成后綴表達式,以便計算機計算。
1 package jjj.arithmetic.methods; 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、CreateShiZi.java
利用代碼隨機產生四則運算式子。
1 package jjj.arithmetic.methods; 2 3 4 public class CreateShiZi { 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 < (int)(Math.random()*10+1); 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 jjj.arithmetic.texts; 2 3 import java.util.Scanner; 4 5 6 import jjj.arithmetic.methods.CreateShiZi; 7 import jjj.arithmetic.methods.NiBoLanShi; 8 9 public class Student { 10 11 public static void main(String[] args) { 12 CreateShiZi createShiZi = new CreateShiZi(); 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實現簡單的四則運算,讓我重拾了以前的基礎知識,譬如數組,列表等等。程序看起來不是很完美,運行時候或許有一些小漏洞,例如隨機產生的四則運算式子中並沒有加入括號;后續也並沒有進行程序的性能分析,由於時間問題及個人能力有限,只能以后再繼續完善了。