Codeforces 295D - Greg and Caves(dp)
結對專案
軟體工程 | https://edu.cnblogs.com/campus/gdgy/informationsecurity1812 |
---|---|
作業要求 | https://edu.cnblogs.com/campus/gdgy/informationsecurity1812/homework/11157 |
作業目標 | 熟悉結對開發專案流程,對結對開發有一定認識 |
結對專案參與者:
-
肖裕海 3118005430
-
鍾景文 3118005434
-
GITHUB地址:https://github.com/mortal-github/mortal-github/tree/autoexam/AutoExamination
PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 30 | 40 |
Estimate | 估計這個任務需要多少時間 | 3000 | 2560 |
Development | 開發 | 1200 | 1350 |
Analysis | 需求分析 (包括學習新技術) | 60 | 60 |
Design Spec | 生成設計文件 | 20 | 30 |
Design Review | 設計複審 (和同事稽核設計文件) | 30 | 15 |
Coding Standard | 程式碼規範 (為目前的開發制定合適的規範) | 30 | 10 |
Design | 具體設計 | 30 | 30 |
Coding | 具體編碼 | 30 | 60 |
Code Review | 程式碼複審 | 15 | 30 |
Test | 測試(自我測試,修改程式碼,提交修改) | 1000 | 780 |
Reporting | 報告 | 30 | 60 |
Test Report | 測試報告 | 30 | 15 |
Size Measurement | 計算工作量 | 15 | 15 |
Postmortem & Process Improvement Plan | 事後總結, 並提出過程改進計劃 | 30 | 60 |
合計 | 5640 | 5115 |
效能分析
效能分析總結
-
效能分析的overview介面很直觀的顯示出程式鎖佔用的記憶體。由此可見,程式的空間複雜度較低。
-
使用的是不可變字串,不會出現重複內容,降低了程式的空間複雜度
各個類的記憶體消耗如圖所示:
設計實現過程與程式碼實現
總體介紹
-
主要的JAVA檔案主要有3個,分別是MyAPP.java,Expression.java,Stack.java和StrictFraction.java
-
MyAPP.java是主程式所在檔案,用於直接執行。
-
Expression.java則是將一系列的作業要求封裝在一起,方便主函式進行呼叫。
-
Stack.java則是自己手寫了一個棧。
-
StrictFraction.java用於執行各種數學運算,類似加減乘除,提取最大公因子等
-
另外還有兩個專用於異常處理的檔案,StrictFractionCalculateException.java和StrictFractionFormatException.java
詳細程式碼實現
- 核心演算法:用逆波蘭表示式實現計算式的儲存與計算
中綴表示式轉換為字尾表示式(逆波蘭表示式)
- 中綴表示式轉字尾表示式主要用到了棧進行運算子處理,佇列進行排序輸出,規則為:
-
數字直接入佇列
-
運算子要與棧頂元素比較
-
棧為空直接入棧
-
運算子優先順序大於棧頂元素優先順序則直接入棧
-
小於或等於則出棧入列,再與棧頂元素進行比較,直到運算子優先順序小於棧頂元素優先順序後,操作符再入棧
-
-
操作符是 ( 則無條件入棧
-
操作符為 ),則依次出棧入列,直到匹配到第一個(為止,此操作符直接捨棄,(直接出棧捨棄
- 具體程式碼:
private static String[] toSuffix(String[] infix)
{
Stack<String> stack = new Stack<>(String.class);
ArrayList<String> suffix = new ArrayList<>();
for(String str : infix)
{
switch(str) {
case "(":
{
stack.push(str);
break;
}
case ")":
{
String push = null;
do {
push = stack.pop();
suffix.add(push);
}while(!push.equals("("));
suffix.remove(suffix.size());
break;
}
case Expression.ADD:
case Expression.SUBTRACT:
{
String push = stack.top();
while(str.equals(Expression.ADD) || str.equals(Expression.SUBTRACT) || str.equals(Expression.TIMES) || str.equals(Expression.DIVIDE))
{//遇到同級別或更高級別操作符就彈棧
push = stack.pop();
suffix.add(push);
push = stack.top();
}
//操作符入棧
stack.push(str);
break;
}
case Expression.TIMES:
case Expression.DIVIDE:
{
String push = stack.top();
while(str.equals(Expression.TIMES) || str.equals(Expression.DIVIDE))
{//遇到同級別或更高級別操作符就彈棧
push = stack.pop();
suffix.add(push);
push = stack.top();
}
//操作符入棧
stack.push(str);
break;
}
default://遇到數字
suffix.add(str);
}
}//end for
return suffix.toArray(new String[suffix.size()]);
}
生成字尾表示式
private static String[] ofSuffix(int[] ops_count, int count_fraction,Supplier<String> fraction, Supplier<String> integer, Predicate<String> op_enable) throws StrictFractionFormatException
private static String[] toInfix(String[] suffix)
private static String[] toSuffix(String[] infix)
-
由這幾個封裝在Expression.java檔案中的方法來實現,具體為先生成字尾表示式之後轉化為中綴表示式輸出
-
其中生成表示式需要用到棧,因此方法對Stack.java檔案進行了呼叫
各種數學計算
private static int divisionAlgorithm(int a, int b)
- 方法實現輾轉相除法
public static int maxCommonFactor(int a, int b)
- 求正值的最大公因子且規定0與任何數的最大公因子為0
public static int minCommonMultiple(int a, int b)
- 求其正值的最小公倍數,不能為0
public static int[] parseArray(String fraction) throws StrictFractionFormatException
- 將字串表示的分數轉換成陣列表示的分數(分母不為0),方便運算,用數字進行運算
public static String parseString(int[] fraction, boolean cut) throws StrictFractionFormatException
- 將陣列表示的分數轉換成字串表示的分數(分母不為0),用於輸出字串表示,方便使用者
答案的輸出與計算式的輸出
try {
Files.deleteIfExists(exercises);
System.out.println("INFO: 成功刪除舊檔案:" + exercises);
Files.deleteIfExists(answers);
System.out.println("INFO: 成功刪除舊檔案:" + answers);
Files.createFile(exercises);
System.out.println("INFO: 成功建立新檔案:" + exercises);
Files.createFile(answers);
System.out.println("INFO: 成功建立新檔案:" + answers);
} catch (IOException e) {
System.out.println( "ERROR: 檔案刪除和創建出現錯誤。\n");
//e.printStackTrace();
}
程式碼覆蓋率
-
主要函式的程式碼覆蓋率相當高
-
例如:
Element | Coverage |
---|---|
MyApp.java | 72.7 % |
Expression.java | 63.6 % |
StrictFraction.java | 80.7 % |
-
其中 Expression.java 中
ofExpression(int[], int, Supplier<String>, Supplier<String>, Predicate<String>)
方法覆蓋率100.0 %
Expression(String[], String[], String)
方法覆蓋率100.0 %
ofExpressionArray(int[], int, Supplier<String>, Supplier<String>, Predicate<String>, int)
方法覆蓋率98.7% -
其中 MyApp.java 中
createAndOutputExpressionToFile(int, int)
方法覆蓋率92.6 %
測試用例
- 本次測試生成了10000個不相同的計算式,設定的r為30。具體執行時間為783ms。
*生成的文件中檢測生成的計算式和答案是否正確
*由上圖易知,程式生成的算式與答案能夠正確匹配
結對感想
肖裕海個人感想
*首先對結對程式設計有了一個具體的認識,知道了結對程式設計如何運做,熟悉了結對程式設計的流程。
*很感謝我的搭檔景文同學,我不明白的程式碼都是靠他來教我,景文同學是一個負責,認真,樂於助人的同學。
*結對程式設計提高了我JAVA書寫程式碼的能力,對各類的理解以及上千行程式碼的專案如何進行debug有一個清晰的理解了。
鍾景文個人感想
*裕海在我寫程式碼的時候及時告訴我他的一些想法,讓我寫程式碼的時候思路更加開闊
*這次結對程式設計再次鍛鍊了我的程式碼能力,讓我能使用Java進行程式碼書寫的時候更加得心應手
*兩個人在一起的時候最重要的還是互相溝通,這次程式設計既鍛鍊了我的程式設計能力,也收穫了與隊友的友誼