作者:謝偉潔3117004673 一、Github項目地址: https://github.com/jack-xie460/mytest.git 二、PSP表格 PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘) Planning 計劃 ...
作者:謝偉潔3117004673
一、Github項目地址: https://github.com/jack-xie460/mytest.git
二、PSP表格
PSP2.1 |
Personal Software Process Stages |
預估耗時(分鐘) |
實際耗時(分鐘) |
Planning |
計劃 |
|
|
· Estimate |
· 估計這個任務需要多少時間 |
|
|
Development |
開發 |
|
|
· Analysis |
· 需求分析 (包括學習新技術) |
|
|
· Design Spec |
· 生成設計文檔 |
|
|
· Design Review |
· 設計覆審 (和同事審核設計文檔) |
|
|
· Coding Standard |
· 代碼規範 (為目前的開發制定合適的規範) |
|
|
· Design |
· 具體設計 |
|
|
· Coding |
· 具體編碼 |
|
|
· Code Review |
· 代碼覆審 |
|
|
· Test |
· 測試(自我測試,修改代碼,提交修改) |
|
|
Reporting |
報告 |
|
|
· Test Report |
· 測試報告 |
|
|
· Size Measurement |
· 計算工作量 |
|
|
· Postmortem & Process Improvement Plan |
· 事後總結, 並提出過程改進計劃 |
|
|
合計 |
|
|
|
三、效能分析
生成10000道50以內的題目耗時340ms
統計10000道題目的對錯耗時119ms
速度還行!
四、實現過程
1.執行Produce類的start方法,程式開始運行,首先通過調用AmountOfNum類來判斷輸入指令是否正確,正確則返回題目數量,
通過調用BoundOfNum類來判斷輸入指令是否正確,正確則返回數值範圍的最大值;
2.Produce類調用Expression類隨機生成表達式,表達式又可通過子表達式和數值之間隨機結合,而子表達式又可通過數值隨機
結合,從而生成各種各樣的表達式;
3.生成的表達式傳入Calculate類,在Calculate中,通過調用houzhuiexp方法將傳入的中綴表達式轉化為尾碼表達式,然後調用
calculate方法調用遞歸方法recusion對尾碼表達式進行計算產生結果,;
4.將產生的題目和結果迴圈列印到相應的文件中;
5.執行Judge類來中的start方法進行對錯統計,首先通過調用ExtractPath類來判斷輸入指令是否正確,正確則返回題目文檔和
答案文檔的路徑,然後進行對錯統計。
6.各個類之間的協同合作圖:
五、代碼說明
1.通過輸入指令生成題目文檔和答案文檔的代碼:
1 package jieduitest01; 2 3 import java.io.File; 4 import java.io.FileWriter; 5 import java.io.IOException; 6 7 //控制台輸入命令,生成題目和答案放在對應文檔中 8 public class Produce 9 { 10 11 public static void start() throws IOException 12 { 13 14 File exerciseFile = new File("E:\\java\\結對作業\\src\\jieduitest01\\Exercises.txt"); 15 File answerFile = new File("E:\\java\\結對作業\\src\\jieduitest01\\Answer.txt"); 16 FileWriter writeToExercisefile =new FileWriter(exerciseFile); 17 FileWriter writeToAnswerfile =new FileWriter(answerFile); 18 19 System.out.println("請輸入您想要生成的題目數量:(例如生成10道題目的格式:-n 10)"); 20 while(!AmountOfExp.method()) {} 21 int amount = AmountOfExp.getAmount(); 22 23 System.out.println("請輸入您想要生成的題目中數值的範圍:(例如數值在10以內格式:-r 10)"); 24 while (!BoundOfNum.method()) {} 25 int bound = BoundOfNum.getBound(); 26 27 String expression; 28 //可變數組存儲尾碼表達式用以查重 29 StringBuilder expressionSet = new StringBuilder(); 30 //迴圈列印題目和答案 31 for(int i=0;i<amount;i++) 32 { 33 expression =Expression.expression(bound); 34 Calculate cal = new Calculate(expression); 35 String houzhuiExp = cal.houzhuiexp(); 36 37 //產生的尾碼表達式與之前的重覆,即產生相同的題目 38 if(expression.indexOf(houzhuiExp)!=-1) 39 { 40 i--; 41 continue; 42 } 43 44 expressionSet.append(houzhuiExp); 45 String result = cal.calculate(); 46 47 //計算過程產生負數 48 if(result.equals("?")) 49 { 50 i--; 51 continue; 52 } 53 54 writeToExercisefile.write(i+1 +" 、" + expression + "="+"\n"); 55 writeToAnswerfile.write(i+1 +"、" + result + "\n" ); 56 57 } 58 writeToExercisefile.close(); 59 writeToAnswerfile.close(); 60 } 61 62 63 }View Code
1 package jieduitest01; 2 3 import java.util.Scanner; 4 import java.util.regex.Matcher; 5 import java.util.regex.Pattern; 6 7 //使用 -n 參數控制生成題目的個數 8 public class AmountOfExp 9 { 10 11 private static int amount; 12 13 public static int getAmount() 14 { 15 return amount; 16 } 17 18 //判斷輸入指令,並從正確輸入指令中提取生成題目的數量 19 public static boolean method() 20 { 21 22 Pattern p = Pattern.compile("(-)(n)(\\s+)(\\d{1,})"); 23 Scanner scan = new Scanner(System.in); 24 String str = scan.nextLine(); 25 Matcher m = p.matcher(str); 26 boolean bo = m.matches(); 27 String[] sarr ; 28 if(!bo) 29 System.out.println("您輸入的格式不合法,請按照格式重新輸入,例如:-n 10"); 30 else 31 { 32 sarr = str.split("\\s+"); 33 amount = Integer.parseInt(sarr[1]); 34 } 35 return bo; 36 } 37 38 }View Code
1 package jieduitest01; 2 3 import java.util.Scanner; 4 import java.util.regex.Matcher; 5 import java.util.regex.Pattern; 6 7 //使用 -r 參數控制題目中數值範圍 8 public class BoundOfNum 9 { 10 11 private static int bound; 12 13 public static int getBound() 14 { 15 return bound; 16 } 17 18 //判斷輸入指令,並從輸入指令中提取題目中數值的範圍 19 public static boolean method() 20 { 21 22 Pattern p = Pattern.compile("-r\\s+\\d+"); 23 Scanner scan = new Scanner(System.in); 24 String str = scan.nextLine(); 25 String[] sarr ; 26 Matcher m = p.matcher(str); 27 boolean bo = m.matches(); 28 if(!bo) 29 System.out.println("您輸入的格式不合法,請按照格式重新輸入,例如:-r 10"); 30 else 31 { 32 sarr = str.split("\\s+"); 33 bound = Integer.parseInt(sarr[1]); 34 } 35 return bo; 36 } 37 38 }View Code
1 package jieduitest01; 2 3 import java.util.Random; 4 5 //生成表達式 6 public class Expression 7 { 8 9 static Random ran=new Random(); 10 11 public static String expression(int bound) 12 { 13 14 String ziexp1 = null,ziexp2 = null; 15 16 //概率結合不同的子表達式 17 int i = ran.nextInt(4); 18 switch(i) 19 { 20 21 case 0: 22 ziexp1 = RandomNum.nextNumber(bound); 23 ziexp2 = RandomNum.nextNumber(bound); 24 break; 25 case 1: 26 ziexp1 = RandomNum.nextNumber(bound); 27 ziexp2 = SubExpression.ziepression(bound); 28 break; 29 case 2: 30 ziexp1 = SubExpression.ziepression(bound); 31 ziexp2 = RandomNum.nextNumber(bound); 32 break; 33 case 3: 34 ziexp1 = SubExpression.ziepression(bound); 35 ziexp2 = SubExpression.ziepression(bound); 36 break; 37 default : 38 } 39 40 String operater = operater(); 41 String exp = ziexp1 +" "+operater+" "+ ziexp2; 42 return exp; 43 } 44 45 46 public static String operater() 47 { 48 49 int opnum = ran.nextInt(4); 50 switch(opnum) 51 { 52 53 case 0: 54 return "+"; 55 case 1: 56 return "-"; 57 case 2: 58 return "×"; 59 case 3: 60 return "÷"; 61 } 62 return null; 63 } 64 65 }View Code
2.將生成的表達式計算出結果的代碼(用到波蘭表達式,即尾碼表達式):
1 package jieduitest01; 2 3 import java.util.HashMap; 4 import java.util.Stack; 5 6 //傳入生成的表達式計算出結果 7 public class Calculate 8 { 9 //用HashMap存儲運算符及其優先順序 10 HashMap<String,Integer> opls; 11 String str0; 12 13 //構造函數,並初始化各個運算符的優先順序 14 public Calculate(String str0) 15 { 16 this.str0 = str0; 17 if(opls==null) 18 { 19 opls = new HashMap<String,Integer>(4); 20 opls.put("+",0); 21 opls.put("-",0); 22 opls.put("×",1); 23 opls.put("÷",1); 24 } 25 } 26 27 //將中綴表達式轉化成尾碼表達式 28 public String houzhuiexp() 29 { 30 //出去空格符 31 String str = str0.replace(" ",""); 32 //將中綴表達式分割放入數組 33 String[] strArray = split(str); 34 //尾碼表達式存儲棧 35 Stack<String> houzhuiSta = new Stack<String>(); 36 //臨時棧 37 Stack<String> temStack = new Stack<String>(); 38 39 for(String src:strArray) 40 { 41 //將操作數直接壓入尾碼表達式的棧 42 if(isNum(src)) 43 houzhuiSta.push("("+src+")"); 44 else //操作數或者括弧 45 { 46 if(temStack.isEmpty()||src.equals("(")) 47 { //"("或臨時棧為空 48 temStack.push(src); 49 } 50 else 51 { 52 if(isLow(temStack.peek(),src)) 53 { 54 if(!src.equals(")")) 55 { ////優先順序比臨時棧棧首值的低 56 while((!temStack.isEmpty())&&(isLow(temStack.peek(),src))) 57 { 58 houzhuiSta.push(temStack.pop()); 59 } 60 temStack.push(src); 61 }else//為")" 62 { //臨時棧棧首的值不為"(" 63 while((!temStack.isEmpty())&&!(temStack.peek().equals("("))) 64 { 65 houzhuiSta.push(temStack.pop()); 66 } 67 //臨時棧棧首的值為"(" 68 if((!temStack.isEmpty())&&(temStack.peek().equals("("))) 69 { 70 temStack.pop(); 71 } 72 } 73 }else 74 { 75 temStack.push(src); 76 } 77 } 78 } 79 } 80 //將臨時棧的剩餘值壓入尾碼棧 81 while(!temStack.empty()) 82 { 83 houzhuiSta.push(temStack.pop()); 84 } 85 //將尾碼棧中的尾碼表達式轉化為字元串返回 86 StringBuilder sb1 = new StringBuilder(); 87 for(String str1:houzhuiSta) 88 { 89 sb1.append(str1); 90 } 91 houzhuiSta.clear(); 92 return sb1.toString(); 93 94 } 95 96 //分割表達式 97 public String[] split(String str) 98 { 99 100 StringBuilder sb = new StringBuilder(str.length()*2); 101 for(char ch:str.toCharArray()) 102 { 103 104 if(ch=='+'||ch=='-'||ch=='×'||ch=='÷'||ch=='('||ch==')') 105 { 106 sb.append(","); 107 sb.append(ch); 108 sb.append(","); 109 } 110 else 111 { 112 sb.append(ch); 113 } 114 } 115 String src = sb.toString().replaceAll(",{2,}",","); 116 return src.split(","); 117 118 } 119 120 //分割尾碼表達式 121 public String[] splitHou(String str) 122 { 123 124 StringBuilder sb = new StringBuilder(str.length()); 125 int i = 0; 126 for(char ch:str.toCharArray()) 127 { 128 if(ch=='+'||ch=='-'||ch=='×'||ch=='÷') 129 { 130 sb.append(","); 131 sb.append(ch); 132 } 133 else if(ch=='('||ch==')') 134 { 135 if(i>=1) 136 { 137 sb.append(','); 138 } 139 } 140 else 141 { 142 sb.append(ch); 143 i++; 144 } 145 } 146 String src = sb.toString().replaceAll(",{2,}",","); 147 return src.split(","); 148 149 } 150 151 //化簡分數 152 String simplify(String exResult) 153 { 154 SplitFra sp = new SplitFra(exResult); 155 int numberater =sp.getNumberater(); 156 int deno =sp.getDeno(); 157 int comDiv = comDivisor(numberater,deno); 158 numberater /= comDiv; 159 deno /= comDiv; 160 int integer = numberater/deno; 161 int fration = numberater%deno; 162 if(integer == 0) 163 { 164 return fration + "/" + deno; 165 }else if (fration == 0) 166 { 167 return integer+""; 168 }else 169 { 170 return integer + "'" + fration + "/" +deno; 171 } 172 } 173 174 //輾轉相除法求最大公約數 175 int comDivisor(int a,int b) 176 { int c = 1; 177 while(a % b != 0) 178 { 179 c = a % b; 180 a = b; 181 b = c; 182 } 183 return b; 184 } 185 186 //判斷是否是操作數 187 public boolean isNum(String str) 188 { 189 for (char ch : str.toCharArray()) 190 { 191 if(ch=='+'||ch=='-'||ch=='×'||ch=='÷'||ch=='('||ch==')') 192 return false; 193 } 194 return true; 195 } 196 197 //比較優先順序 198 public boolean isLow(String pop, String str) 199 { 200 if(str.equals(")")) 201 return true; 202 if(opls.get(pop)==null||opls.get(str)==null) 203 return false; 204 return opls.get(pop)>=opls.get(str); 205 } 206 207 //調用遞歸方法利用尾碼表達式計算結果 208 public String calculate() 209 { 210 //尾碼表達式 211 String houhzhuiExp = houzhuiexp(); 212 String[] strs = splitHou(houzhuiexp()); 213 //調用遞歸得到結果 214 String exResult = recursion(strs); 215 //計算過程產生負數返回"?" 216 if(exResult.equals("?")) 217 { 218 return "?"; 219 } 220 String result ; 221 //結果是分數,化簡 222 if(exResult.contains("/")) 223 { 224 result = simplify(exResult); 225 }else 226 { 227 result = exResult; 228 } 229 return result; 230 } 231 //遞歸方法 232 public String recursion(String[] str) 233 { 234 //計算過程是否出現負數的標記 235 boolean flag = false; 236 int nowlength = str.length; 237 if(str[str.length-1]==" ") 238 { 239 nowlength = str.length-1; 240 }else if(str.length == 1) //尾碼表達式長度為1則遞歸結束返回結果 241 { 242 return str[0]; 243 } 244 String[] nextstr = new String[nowlength-2]; 245 for(int i = 2;i<nowlength;i++) 246 { 247 248 if(str[i].equals("+")||str[i].equals("-")||str[i].equals("×")||str[i].equals("÷")) 249 { 250 String num1 = str[i-2]; 251 String num2 = str[i-1]; 252 String operater = str[i]; 253 String result; 254 switch(operater) 255 { 256 case "+": 257 result = Math.add(num1,num2)