項目 | 內容 |
---|---|
這個做業屬於哪一個課程 | https://edu.cnblogs.com/campus/buaa/BUAA_SE_2019_LJ |
這個做業的要求在哪裏 | https://edu.cnblogs.com/campus/buaa/BUAA_SE_2019_LJ/homework/2638 |
我在這個課程的目標是 | 熟悉結對編程流程,進行一次結對開發 |
這個做業在哪一個具體方面幫助我實現目標 | 進行結對編程實踐,瞭解告終對編程的優缺點 |
最長單詞鏈項目html
PSP 2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 1830 | |
· Estimate | · 估計這個任務須要多少時間 | 1830 | |
Development | 開發 | 1620 | |
· Analysis | · 需求分析 (包括學習新技術) | 200 | |
· Design Spec | · 生成設計文檔 | 60 | |
· Design Review | · 設計複審 (和同事審覈設計文檔) | 30 | |
· Coding Standard | · 代碼規範 (爲目前的開發制定合適的規範) | 30 | |
· Design | · 具體設計 | 200 | |
· Coding | · 具體編碼 | 600 | |
· Code Review | · 代碼複審 | 200 | |
· Test | · 測試(自我測試,修改代碼,提交修改) | 300 | |
Reporting | 報告 | 210 | |
· Test Report | · 測試報告 | 150 | |
· Size Measurement | · 計算工做量 | 30 | |
· Postmortem & Process Improvement Plan | · 過後總結, 並提出過程改進計劃 | 30 | |
合計 | 1830 |
Information Hiding(信息隱藏)原則,是David Parnas在1972年最先提出信息隱藏的觀點。他在其論文中指出:代碼模塊應該採用定義良好的接口來封裝,這些模塊的內部結構應該是程序員的私有財產,外部是不可見的。是指程序的具體實如今外部是不可見的,只暴露出一些接口。
Interface Design,良好的接口設計須要遵循單一職責原則,開放-封閉原則,里氏替換原則等,在本次做業中,Core類只暴露出2個接口。
Loose Coupling,鬆耦合,一個模塊對另外一個模塊的調用較少。
在本次做業設計中,Core模塊僅暴露出2個接口gen_chain_word()和gen_chain_char(),用戶對於內部的具體實現是不知道的。node
計算模塊包含一個Core類,其中僅有兩個可供外部調用的接口:git
int gen_chain_word(char* words[], int len, char* result[], char head, char tail, bool enable_loop); int gen_chain_char(char* words[], int len, char* result[], char head, char tail, bool enable_loop);
Core類中的其餘函數:程序員
void newnode(string word); void addtomap(node newword); void toforest(); void next1(vector<int> forward, int root); void next2(vector<int> forward, int root); int findmostwords(char head, char tail); int findlongest(char head, char tail); int listlength(int index);
各函數之間的調用流程圖以下:
github
算法大體思路:
根據單詞鏈的定義,一個單詞的最後一個字母等於另外一個單詞的第一個字母,故想到用有向圖來實現。算法
花費時間:
改進計算模塊性能所花費的時間:2小時。編程
改進思路:
第一個版本的程序中,不管面對什麼狀況,都會把有向圖中的大大小小的全部鏈路都分出來,花費了大量的時間。在不約束首位字母和只約束首字母的狀況下,只按照各個根節點來生成最長的單詞鏈。在約束尾字母的狀況下,再加入對尾字母的判斷,生成更多的鏈。app
性能分析圖以下:
ide
從性能分析圖來看,消耗最大的函數是listlength(),該函數用來計算單詞鏈的長度,具體代碼以下:函數
int Core::listlength(int index) { int sum = 0; int i = 0; for (i = 0; i < forest[index].size(); i++) { sum += map[forest[index][i]].wordlen; } return sum; }
Design by Contract(契約編程),Design by Contract使用了三類斷言:後繼條件(post-conditions),前提條件(pre-conditions),以及不變量(invariants)。
契約編程好處在於程序員只需按照以前制定好的契約來對本身的代碼負責,可是契約式編程很是的繁瑣,這也就是缺點。
在咱們本次的做業中,並無嚴格知足契約式編程。
對Core模塊進行了多個測試,如下舉出2例
測試示例一代碼以下:
TEST_METHOD(TestMethod5)//-h a -t t -w { Core* core = new Core(); char* result[100]; char* words[] = { "abbbb","bcccc","cdddd","deee","ct" }; char* answer[] = { "abbbb","bcccc","ct"}; int answerlen = 3; int resultlen = core->gen_chain_word(words, 5, result, 'a', 't', false); Assert::AreEqual(resultlen, answerlen); int i = 0; for (i = 0; i < answerlen; i++) { string stranswer = answer[i]; string strresult = result[i]; Assert::AreEqual(stranswer, strresult); } }
這是一個約束單詞鏈首字母爲a,末尾字母爲t,單詞數量最多的測試,調用Core模塊中的gen_chain_word接口。這是一個測試程序可否正確跑對的測試。
測試示例二代碼以下:
TEST_METHOD(TestMethod8)//-h b -t t -c { Core* core = new Core(); char* result[100]; char* words[] = { "abb","bccccccccccccccccccccc","cccccccccccccccccccccf","ctttt","cbt" }; char* answer[] = { "bccccccccccccccccccccc","ctttt" }; int answerlen = 2; int resultlen = core->gen_chain_char(words, 5, result, 'b', 't', false); Assert::AreEqual(resultlen, answerlen); int i = 0; for (i = 0; i < answerlen; i++) { string stranswer = answer[i]; string strresult = result[i]; Assert::AreEqual(stranswer, strresult); } }
這個測試一樣也是約束首尾字母分別爲b,t的測試,但不一樣的是,要求輸出字母最多的單詞鏈,在所給的輸入數字中存在一個干擾項,即「bccccccccccccccccccccc」,"cbt"。來檢驗程序是否可以正確執行。
在Core模塊的單元測試中,總共構造了12個測試。獲得的測試覆蓋率以下:
此異常應對當輸入的單詞可以構成單詞環可是並無輸入-r參數的狀況。
單元測試樣例以下
TEST_METHOD(ErrorTest1)//包含單詞環可是沒有-r參數 { Core* core = new Core(); char* result[100]; char* words[] = { "apple","elephant","tea","alex","box","xob","cccccff","football","lllllllllllllllllllllllllllllllllllllllllllllllllllllllllc" }; char* answer[] = { "football","lllllllllllllllllllllllllllllllllllllllllllllllllllllllllc","cccccff" }; int answerlen = 3; try { int resultlen = core->gen_chain_char(words, 9, result, '\0', 'f', false); } catch (exception e) { Assert::AreEqual("單詞文本隱含單詞環", e.what()); } }
其中 football -- llllllllllllllc --- cccccff 能造成單詞環,可是 enable_loop 傳入 false,應該拋出「單詞文本隱含單詞環」異常。
計算模塊接口經過char* words[] 來傳入所有單詞,若是單詞字符串中出現不是字母的狀況,就應該拋出此異常。
單元測試樣例以下
TEST_METHOD(ErrorTest2)//輸入的單詞中有非法字符,elephant 的字母l被空格代替 { Core* core = new Core(); char* result[100]; char* words[] = { "apple","e ephant","tea","alex","box","xob","cccccff","football","lllllllllllllllllllllllllllllllllllllllllllllllllllllllllc" }; char* answer[] = { "football","lllllllllllllllllllllllllllllllllllllllllllllllllllllllllc","cccccff" }; int answerlen = 3; try { int resultlen = core->gen_chain_char(words, 9, result, '\0', 'f', false); } catch (exception e) { Assert::AreEqual("單詞包含非法字符", e.what()); } }
輸入的單詞中的第二個單詞"e ephant"的第二個字符不是字母,應該拋出」單詞包含非法字符「異常。
當傳入的head 和 tail 參數既不是合法字母,也不是'\0'字符時拋出異常。
單元測試樣例以下
TEST_METHOD(ErrorTest3)//首尾字母約束不合法,用 -h * { Core* core = new Core(); char* result[100]; char* words[] = { "apple","elephant","tea","alex","box","xob","cccccff","football","lllllllllllllllllllllllllllllllllllllllllllllllllllllllllc" }; char* answer[] = { "football","lllllllllllllllllllllllllllllllllllllllllllllllllllllllllc","cccccff" }; int answerlen = 3; try { int resultlen = core->gen_chain_char(words, 9, result, '*', '\0', false); } catch (exception e) { Assert::AreEqual("首尾字母約束不合法", e.what()); } }
在調用gen_chain_char()時,head參數輸入爲'*',既不是字母也不是'\0',不合法,應當拋出「首尾字母約束不合法」異常。
當傳入的words[]中有空字符串的時候,拋出此異常。
單元測試樣例以下
TEST_METHOD(ErrorTest5)//有單詞爲空字符串 " { Core* core = new Core(); char* result[100]; char* words[] = { "apple","","tea","alex","box","xob","cccccff","football","lllllllllllllllllllllllllllllllllllllllllllllllllllllllllc" }; char* answer[] = { "football","lllllllllllllllllllllllllllllllllllllllllllllllllllllllllc","cccccff" }; int answerlen = 3; try { int resultlen = core->gen_chain_char(words, 9, result, '\0', '\0', false); } catch (exception e) { Assert::AreEqual("有單詞爲空字符串", e.what()); } }
傳入的words[]中的第二個是 「」 , 爲空字符串,應當拋出「有單詞爲空字符串」異常。
(1)首先經過main函數從命令行中獲取參數的個數和具體的參數
int main(int argc, char* argv[])
從第二個參數開始依次讀取argv[]中的參數,與"-h","-t","-r","-w","-c"這五個參數進行比較,進行具體處理。
若是是"-h"或者"-t"這兩個約束首尾字母的參數,則直接讀取argv[]中的下一個參數,根據規則,緊跟着的下一個參數應該是字母,若是不是則報錯。
若是是「-w"或者「-c」這兩個參數,則直接讀取argv[]中的下一個參數,根據規則,緊跟着的下一個參數應該是單詞文本的路徑,若是不是則報錯。
其中,「-w","-c"參數不能同時存在,"-h",」-t「參數能夠同時存在,同一個參數不能出現兩次,所以增長了五個布爾類型的變量進行是否重複的判斷。
以判斷」-h「參數爲例,部分代碼以下
for (i = 1; i < argc; i++) { parameter = argv[i]; if (strcmp(parameter, "-h") == 0) { if (if_head) { cout << "錯誤:-h參數重複" << endl; exit(0); } if_head = true; i++; parameter = argv[i]; if (strlen(parameter) == 1 && isalpha(parameter[0])) { head_alpha = parameter[0]; } else { cout << "錯誤:-h後沒有字母" << endl; exit(0); } }
在main函數讀入參數以後,直接進行命令行參數的處理,判斷參數都正確以後,根據"-w" 和 "-c" 參數來分別調用Core模塊中的兩個接口進行計算
if (if_word) { resultlen = core->gen_chain_word(words, wordslen, result, head_alpha, tail_alpha, if_roun); } else if (if_char) { resultlen = core->gen_chain_char(words, wordslen, result, head_alpha, tail_alpha, if_roun); }
PSP 2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | ||
· Estimate | · 估計這個任務須要多少時間 | 1830 | 1430 |
Development | 開發 | ||
· Analysis | · 需求分析 (包括學習新技術) | 200 | 180 |
· Design Spec | · 生成設計文檔 | 60 | 20 |
· Design Review | · 設計複審 (和同事審覈設計文檔) | 30 | 10 |
· Coding Standard | · 代碼規範 (爲目前的開發制定合適的規範) | 30 | 10 |
· Design | · 具體設計 | 200 | 30 |
· Coding | · 具體編碼 | 600 | 600 |
· Code Review | · 代碼複審 | 200 | 180 |
· Test | · 測試(自我測試,修改代碼,提交修改) | 300 | 220 |
Reporting | 報告 | ||
· Test Report | · 測試報告 | 150 | 200 |
· Size Measurement | · 計算工做量 | 30 | 10 |
· Postmortem & Process Improvement Plan | · 過後總結, 並提出過程改進計劃 | 30 | 10 |
合計 | 1830 | 1430 |