利用Visio進行流程圖的繪制,具體流程圖如下:其中ContentToTxt(將結果寫入文件) Main(主程序可以從命令行接收參數) ReversePolish (逆波蘭表達式) RandomEquation(產生等式) result.txt(運行后產生的結果)
1) 隨機產生等式模塊:為了看起來整潔,去掉了測試過程中注釋掉的打印輸出部分。等式生成是將生成的數字與運算符依次拼接,之后加上等號構成等式,在構建過程中去除運算符只有一種的情況、分母為0的情況,分子分母有余數的情況。
1 public class RandomEquation { 2 public static String randomEquation (){ 3 4 // Previous expressions 5 6 String sBefore = new String(); 7 8 // The later expression 9 10 String sLater = new String(); 11 char[] equation; 12 int k = 6; 13 int n; 14 int m; 15 int j; 16 int i; 17 int[] number; 18 char[] symbol; 19 number = new int[k]; 20 symbol = new char[k]; 21 equation = new char[2 * k]; 22 char[] cSymbol = {'+','-','*','÷'}; 23 Random random = new Random(); 24 25 // Generating operator 26 27 for(i = 0;i<(int)(Math.random()*3)+3;i++){ 28 int index = random.nextInt(cSymbol .length); 29 char resultChar = cSymbol[index]; 30 symbol[i] = resultChar; 31 32 } 33 for(m = 0;m < i;m++){ 34 if(symbol[i - 1] != symbol[m]){ 35 break; 36 } 37 } 38 39 /* 40 * Removal of only one operator 41 * If the last symbol is the same as the previous one, the last one generates a symbol at random. 42 */ 43 44 if(m == i){ 45 do{ 46 int index = random.nextInt(cSymbol.length); 47 char resultChar = cSymbol[index]; 48 symbol[i - 1] = resultChar; 49 }while(symbol[i - 1] == symbol[i - 2]); 50 } 51 52 // Generating number 53 54 for(j = 0;j < i + 1;j++){ 55 56 int num = (int)(Math.random()*100); 57 number[j] = num; 58 59 } 60 61 // Generating equation 62 63 for(n = 0;n < i;n++){ 64 sBefore += String.valueOf(number[n])+String.valueOf(symbol[n]); 65 } 66 sBefore += String.valueOf(number[i]); 67 68 // Save symbols and numbers into a equation array 69 70 for(n = 1;n < 2 * i;n = n+2){ 71 72 equation[n] = symbol[(n - 1) / 2]; 73 } 74 for(n = 0;n < 2 * j - 1;n = n+2){ 75 76 equation[n] = (char)number[(n + 1) / 2]; 77 78 } 79 80 // The removal ÷ denominator is 0 and the molecular denominator is incompatible 81 82 for(n = 1;n < i + j && n + 1 < i + j;n = n + 2){ 83 if(equation[n] == '÷'){ 84 if(equation[n + 1]==0){ 85 do{ 86 int num2 = (int)(Math.random()*100); 87 equation[n + 1] = (char)num2; 88 }while(equation[n + 1] == 0); 89 } 90 else if((int)equation[n - 1] % (int)equation[n + 1]!=0 || (int)equation[n - 1]<(int)equation[n + 1]){ 91 do{ 92 93 int num2 = (int)(Math.random()*100) + 1; 94 equation[n + 1] = (char)num2; 95 if(equation[n + 1] == 0){ 96 do{ 97 int num3 = (int)(Math.random()*100); 98 equation[n + 1] = (char)num3; 99 }while(equation[n + 1] == 0); 100 } 101 102 }while((int)equation[n - 1] % (int)equation[n + 1]!= 0 || (int)equation[n - 1]<(int)equation[n + 1]); 103 } 104 105 } 106 107 108 } 109 // The equation after excluding special circumstances 110 111 for(n = 0;n < i+j && n + 1 < i + j;n = n + 2){ 112 113 sLater += String.valueOf((int)equation[n]); 114 sLater += String.valueOf(equation[n + 1]); 115 116 } 117 sLater += String.valueOf((int)equation[i + j - 1]); 118 sLater += String.valueOf('='); 119 120 return sLater; 121 } 122 123 }
2)逆波蘭模塊借鑒這位博主的寫法,並在理解的基礎上進行了代碼的加工。當中間結果小於0或者a%b!=0時,利用return跳出該函數,並在下邊的模塊中利用返回值進行等式的重新生成。 http://blog.csdn.net/u010485491/article/details/51483720
1 public static int calcInt(int a, int b, String stmp) 2 { 3 int res = 0; 4 char s = stmp.charAt(0); 5 switch (s) { 6 case '+': { 7 res = a + b; 8 break; 9 } 10 case '-': { 11 res = a - b; 12 if(res < 0){ 13 return -1; 14 } 15 break; 16 } 17 case '*': { 18 res = a * b; 19 break; 20 } 21 case '÷': { 22 res = a / b; 23 if( a % b != 0){ 24 return -1; 25 } 26 break; 27 } 28 } 29 return res; 30 }
3)結果寫入文件模塊,由於隨機產生等式,所以需要一直將該等式保存到字符串里,並對該字符串進行逆波蘭求解,否則若隨機產生式子randomEquation(),之后又利用ReversePolish(randomEquation()))產生的隨機等式的結果,這樣會出現等式計算結果與最終運算結果不匹配的情況。在該模塊中利用返回值的不同進行結果的保存,若返回值為-1或者大於用戶輸入的結果值result,就將i的值自減,這樣就相當於重新產生符合條件的式子。
1 for(int i = 0;i < questionAmount;i++){ 2 3 String randoms = randomEqual.randomEquation(); 4 final boolean existed = reversePolish.reversePolish(randoms) != -1 && reversePolish.reversePolish(randoms) < 500; 5 if(existed){ 6 7 contentToTxt.contentToTxt(strFilePath,String.valueOf(randoms+reversePolish.reversePolish(randoms))); 8 contentToTxt.contentToTxt(strFilePath,String.valueOf("\n")); 9 }else{ 10 i--; 11 } 12 }
總結:
- 在拿到題目的時候,並沒有急着去完成代碼而是首先進行了需求分析,根據需求分析將本次作業分為三大模塊,並對這三個模塊進行了功能的划分,每個模塊都有要實現的功能,且盡量降低模塊之間的聯系。以這樣的做法書寫下來發現思路很清晰,由於不再在一個函數體內書寫程序,一個模塊出了問題不必全篇找,直接在這個模塊中修改即可。
- 由於參加完藍橋杯之后就沒有與java打交道了,一直與c語言打交道,所以java當中的語法也遺忘了不少,使用new這一關鍵字創建對象也給忘記啦,突然想到一則笑話(甲說都大三了,連女朋友都沒有。乙說:new一個‘對象’),這下子就忘不了啦。
- 在書寫代碼的過程中使用了do while語句,不需要判斷循環次數,以前一直在使用while語句,這次在產生表達式的過程中大量使用了do while,深刻體會到了該語句的妙處。
- 在考慮情況的時候並不是一次性完成的,而是在編寫代碼的過程中慢慢想出來的,到了最后計算結果的時候發現結果已經有上萬的啦,所以將輸出結果限制在用戶要求的范圍內,這樣就和小學生實際情況相符合。
- 在生成表達式中去除分子分母不能整除的時候,例如a/b/c判斷,若a/b不能整除就再隨機產生a,b;若同時b/c不能整除則再隨機產生b,c;這樣下來發現會產生a/b不能整除的情況,因為b隨機了兩次,后一次隨機就無法保證a/b是整數了,所以想到在逆波蘭計算的時候進一步排除連續除號除不盡的情況。
- 最后寫的是文件模塊,由於是將之前寫的文檔import進去的,在測試是否寫好文件的時候發現在目錄JRE System Library下邊沒有產生文件,最后在打開的文件夾中找到了,所以之后的每一次運行就拿Windows自帶的記事本打開,明明寫了換行符但仍在一行上,測試了好幾次都不對,最后和同學交流了才發現這個問題,利用notepad++打開結果就是合適的。
- 本來是想進行附加功能的添加,然而做的時候將一些特殊請款考慮到生成表達式的模塊中,導致這些附加功能無法實現,比如真分數的計算,在生成表達式的過程中,將分子分母除不盡的情況已經排除,另外就是加括號的情況,在此模塊中將除法中出現的分母為零的情況排除,排除的時候只看除號后邊的數字,如果加上括號就沒辦法進行特殊情況的判斷。所以還是在寫的時候全盤考慮,不能只想着實現這些基本功能,使得算法沒有拓展性。
PSP:
PSP2.1 | 任務內容 | 計划完成需要的時間(min) | 實際完成需要的時間(min) |
Planning | 計划 | 20 | 25 |
Estimate | 估計這個任務需要多少時間,並規划大致工作步驟 | 20 | 25 |
Development | 開發 | 360 | 418 |
Analysis | 需求分析 (包括學習新技術) | 10 |
10 |
Design Spec | 生成設計文檔 | 10 | 8 |
Design Review | 設計復審 (和同事審核設計文檔) | 10 | 15 |
Coding Standard | 代碼規范 (為目前的開發制定合適的規范) | 20 | 20 |
Design | 具體設計 | 30 | 35 |
Coding | 具體編碼 | 240 | 280 |
Code Review | 代碼復審 | 20 | 25 |
Test | 測試(自我測試,修改代碼,提交修改) | 20 | 25 |
Reporting | 報告 | 20 | 27 |
Test Report | 測試報告 | 5 | 5 |
Size Measurement | 計算工作量 | 5 | 12 |
Postmortem & Process Improvement Plan | 事后總結 ,並提出過程改進計划 | 10 | 10 |