Tips | Link |
---|---|
做業連接 | [2019BUAA軟件工程]結對做業 |
GitHub地址 | WordChain |
psp2.1 | 預估耗時(分鐘) | 實際耗時(分鐘) | |
---|---|---|---|
Planning | 計劃 | 60 | 40 |
. Estimate | · 估計這個任務須要多少時間 | 900 | 1200 |
Development | 開發 | 700 | 900 |
. Analysis | · 需求分析 (包括學習新技術) | 60 | 60 |
. Design Spec | · 生成設計文檔 | 100 | 120 |
.Design Review | · 設計複審 (和同事審覈設計文檔) | 40 | 20 |
.Coding Standard | 40 | 30 | |
.Design | · 具體設計 | 60 | 50 |
.Coding | · 具體編碼 | 200 | 320 |
.Code Review | · 代碼複審 | 100 | 200 |
.Test | · 測試(自我測試,修改代碼,提交修改) | 100 | 100 |
Reporting | 報告 | 200 | 300 |
.Test Report | · 測試報告 | 60 | 100 |
.Size Measurement | · 計算工做量 | 100 | 120 |
.Postmortem & Process Improvement Plan | · 過後總結, 並提出過程改進計劃 | 40 | 80 |
合計 | 960 | 1240 |
In computer science, information hiding is the principle of segregation of the design decisions in a computer program that are most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed. The protection involves providing a stable interface which protects the remainder of the program from the implementation (the details that are most likely to change). git
以上部分摘自維基百科中對information hidding定義。信息隱藏的主要實現方式即便對咱們本身程序的封裝,好比將功能穩定的函數,抽象出來封裝爲私有,以實如今作出修改時,儘量的保證程序其他部分的正確性,減小維護難度。另外一方面,將程序中的變量都封裝位私有,將這些信息隱藏起來,也能夠較好的保證用戶信息安全。github
在咱們的程序中,咱們採用將不少功能抽象出子函數,只給用戶暴漏了一個計算的入口函數,較好的實現了信息封裝以及程序的可維護性,全部的變量也都採用私有變量的形式,加強了信息安全的可靠性。算法
User interface design (UI) or user interface engineering is the design of user interfaces for machines and software, such as computers, home appliances, mobile devices, and other electronic devices, with the focus on maximizing usability and the user experience.編程
以上部分摘自維基百科中對interface design 定義。接口設計的主要目的,是爲了其餘的用戶或者應用提供一個應用或者用戶能夠直接使用的功能接口(即便別人徹底不知道內部實現也能夠輕易使用),原則就是封裝的越徹底越好,接口調用越簡單越好。在咱們的程序中,採用和做業指導中相同的接口設計,一方面實現了對程序功能較好的封裝,一方面也極大的方便了咱們與其餘同窗的耦合。後端
In computing and systems design a loosely coupled system is one in which each of its components has, or makes use of, little or no knowledge of the definitions of other separate components. Subareas include the coupling of classes, interfaces, data, and services.[1] Loose coupling is the opposite of tight coupling.數組
以上部分摘自維基百科中對loose coupling定義. 程序中模塊之間的耦合性主要是體如今模塊之間的依賴關係,下降模塊之間的耦合性,既能夠最大程度上的實現模塊中的功能分離,也能夠更方便的對模塊的功能之間進行測試。在咱們的程序中方,咱們將數據出來模塊,與運算 模塊徹底獨立 開,經過接口傳遞數據,極大的下降了模塊之間的依關係,也較好的方便了對每一個模塊正確性的單獨測試。安全
接口:app
bool gen_chain_word(vector<string> &words, vector<string> &output, char head, char tail, bool enable_loop);
bool gen_chain_char(vector<string> &words, vector<string> &output, char head, char tail, bool enable_loop);
參數解釋:electron
vector<string> &words:傳入單詞集合。模塊化
vector<string> &output:輸出單詞鏈。
char head:單詞鏈首字母限制。無限制輸入0,有限制則輸入相應英文字符。
char tail:單詞鏈首字母限制。無限制輸入0,有限制則輸入相應英文字符。
bool enable_loop:單詞環限制。容許存在單詞換爲true,不然爲false。
Core:內外層交互類
實現計算模塊與外層(Console或GUI模塊)交互邏輯。
接收外層的原始數據和相應參數。
對接收到的原始數據進行預處理:
從原始數據中提取出單詞。
過濾重複單詞。
將有效單詞按首尾字母歸類,存入單詞庫中。
更新單詞庫中單詞連接矩陣。
按照指定模式組織內層計算邏輯。
返回內層計算結果。
Solve/DPSolve:核心計算類
實現對已有單詞庫搜索單詞鏈的算法。
核心算法:優化BFS(有單詞環)和動態規劃(無單詞環)。
輔助算法:拓撲排序(檢查是否存在單詞環)。
WordList:數據類
格式化存儲單詞。
將單詞連接關係組織爲鄰接矩陣。
提供相應的查詢函數。
Core獲取原始數據與運行參數。
Core預處理原始數據,生成單詞庫(WordList)。
按照參數啓動Solve/DPSolve相應計算函數。
完成單詞鏈搜索,Core輸出計算結果。
Core:
關鍵函數:
gen_chain_word():按單詞數量搜索單詞鏈時的對外接口。
gen_chain_char():按單詞長度搜索單詞鏈時的對外接口。
WordList:
存儲結構設計思路:
單詞表組織: 將消除重複後的單詞按照首尾字母進行歸類。好比:apple歸類爲ae類單詞。爲每一種類的單詞創建數組存儲,每一個數組內的同種單詞按照長度降序排列。對存儲每一種類單詞的數組按照HASH表存儲至一維數組中。
輔助結構組織: 根據已經創建的單詞表,將字母視爲節點,單詞視爲由首字母結點指向尾字母的有向邊,則可以將單詞表組織爲有向圖。使用位圖存儲鄰接矩陣,使用HASH數組存儲各結點的入度。
HASH函數:Index = 首字母相對'a'偏移 * 26 + 尾字母相對'a'偏移
成員變量:
m_list:單詞表,按照首尾字母的種類對單詞進行分組儲存,存儲採用HASH結構,不存在重複單詞,同種類單詞按照長度由長至短排列。
m_iListSize:單詞表長度,存儲不一樣首尾字母的單詞數量。
m_iListGetPoint:單詞檢索索引,存儲已檢索的單詞的索引。
m_iArryMatrix[]:單詞鏈鄰接矩陣。
m_iArrayNodeIn[]:結點入度數組。
關鍵函數:
parseString():
解析字符串,提取單詞。
調用私有函數addWord添加單詞。
getWordAt():
獲取符合首尾條件的單詞。
可以支持對相同單詞的不重複搜索與重複搜索。
getWordSumAt():
獲取符合首尾條件的單詞總數量。
getWordRemainingAt():
獲取符合首尾條件的單詞剩餘數量。
剩餘數量指未被操做搜索過的單詞。
undoGetWordAt():
撤銷單詞不重複搜索操做,即撤銷對某首尾單詞的前一次不重複搜索操做。
getNodeIn():
獲取單詞鏈圖某一首字母結點的入度。
getNodeNext():
獲取單詞鏈圖某一首字母結點的鄰接矩陣項。
addWord():"private"
過濾重複單詞,將有效單詞添加至單詞表相應分類。
保證添加後各分類內單詞長度降序排列。
Solve:
實驗思路
使用深度優先搜索加剪枝策略,解決了頭尾限定問題,以及屬於單詞序列中存在環時得問題。
成員變量:
word
m_iSigned26 標記兩個字母之間的路徑是否以及走過
m_ihead[26] 標記每一個字母是否以及用過
m_ans676 記錄單詞是否使用的變量
next_tag26 儲存字母鄰接鏈表
max_dfs[26] 記錄每一個單詞距離終點的最大距離
final_dfs[26] 記錄最終的每一個字母節點距離其重點的距離
m_FinalLen 單詞鏈最終長度
m_TemLen 搜索到的當前字符鏈的長度
max_num 單詞鏈個數最大長度
temp_num 搜索到的單詞鏈表當前個數
bool is_circle 判斷是否有環
head 肯定頭部字母記錄下的頭部字母
char m_Mode 記錄搜索模式的變量
char m_ModeHead 記錄搜索的時指定的頭部
char m_ModeTail 記錄搜索的時指定的尾部
bool m_ModeRing 記錄搜索模式是否有環
vector <string> m_FinalChain; 最終結果
vector <string> m_TempChain; 當前路徑
關鍵方法
Solve1() 解決容許有環時的搜索問題
Solve2_he() 解決無環時的指定頭尾的搜索問題
Dfs_solve1() 解決容許有環時的搜索問題的搜索函數
cmp() 容許有環的時候對當前最大長度的更新函數
printChain() 容許有環的時候的輸出函數
Dfs_solvehe() 指定頭尾問題的搜索問題的遞歸搜索函數
cmp_he() 解決頭尾指定問題時候 對當前最大長度進行更新的函數
printhe() 解決頭尾指定問題時候 的輸出問題
DPSolve:
實現思路:
使用動態規劃解決無單詞環狀況下除同時限定單詞鏈首尾的問題。根據限制條件的不一樣採起正向或逆向動態規劃。
動態規劃:
正向遞推式:F(c1)=max{F(c1)+len(c1ci)}或F(c1)=max{F(c1)+len(c1ci)}
逆向遞推式:f(c1)=max{f(c1)+len(cic1)}或f(c1)=max{f(c1)+len(cic1)}
F(c)爲由c開始的最長單詞鏈長度。
f(c)爲以c結束的最長單詞鏈長度。
len(cicj)是以ci爲首以cj爲尾的最長單詞長度。
單詞環檢測:
使用拓撲排序算法檢測單詞環,保證動態規劃正確進行。
成員變量:
m_ptrWordList:單詞表指針。
m_cMode:搜索模式,分爲按數量和按程度。
m_cModeHead:頭部限定。
m_cModeTail:尾部限定。
m_iArrayDp[]:動態規劃結果。
m_iArrayNext[]:存儲相應結點的最優後繼結點。
m_iArrayBefore[]:存儲相應結點的最優前綴結點。
m_iQueueTopo:拓撲排序結果。
m_strVecWordChain:存儲計算獲得的單詞鏈。
關鍵方法:
DPSolve():構造函數,傳入單詞表和各類參數。
startDPSolve():啓動函數。
topoSort():拓撲排序,檢查單詞表中是否有環。
getWordChain():導出計算後的結果。
DPStep(int indexH):正向動態規劃子函數,私有函數。
DPStepRe(int indexH):逆向動態規劃子函數,私有函數。
第一階段:深度搜索實現基本功能
筆者在最初進行程序設計時採起的是使用簡潔的方法先實現需求的全部功能,再根據實際運行狀況優化算法。根據這樣的初衷產生了以下的流程設計。 首先,將全部單詞按照首尾字母進行分類。以字母爲結點,以單詞爲有向邊(由單詞首字母結點指向尾字母節點),將單詞表構形成圖結構。如此組織單詞表能夠很好地對需求中的問題進行簡化和抽象:無單詞環時,很容易證實每一個結點間最多單向通過一次。好比'a'、'b'兩結點最多僅能有一個有向邊。因而即可以將問題轉化爲在構造的圖中搜索最長路徑。對於‘-w’功能則是將邊權重設置爲‘1’;對於‘-c’功能則是將邊權重設置爲該邊對應類型單詞中最長的單詞長度;而‘-t’和‘-h’功能則是增長了首尾節點的限制。而對於有單詞環的狀況,每一個結點間可通過的方向及其次數等於其所對應種類的單詞數量,運用深度搜索也一樣可以解決相應的問題。 在搜索階段,程序對每一個節點進行深度搜索,搜索以該結點爲首的最長路徑,並根據不一樣的輸入參數得出符合要求的單詞鏈。最終經過接口完成結果的輸出。
第二階段:動態規劃優化部分功能
筆者的小組在較短期內就完成了基於深度搜索的單詞鏈搜索程序。在經過正確性測試並進行性能測試後,不出意料的出現的運行效率低的問題。運行效率低的主要緣由是原始深度遍歷不具備記憶和預測功能。這會致使在進行屢次遍歷時會對以搜索的路徑和明顯不是最優解的路徑進行遍歷。會通過分析後,咱們決定採起如下方案對程序進行優化。 對於無單詞環而且不一樣時限定首尾的狀況,廢棄原先的方法轉而採用動態規劃的方法。這幾個搜索最長單詞鏈的問題能夠分解爲求解與其相連的字母的最長單詞鏈加上二者間距離的最大值。好比正向動態規劃時,求解以'a'爲首的最長單詞鏈,而'b'、'c'結點能夠由'a'結點直接到達,則原問題的最優解爲子問題'b'、'c'的最優解分別加上'a'到這些結點的邊的權值。用公式表示爲: 正向遞推式:F(c1)=max{F(c1)+len(c1ci)}*或*F(c1)=max{F(c1)+len(c1ci)}
逆向遞推式:f(c1)=max{f(c1)+len(cic1)}*或*f(c1)=max{f(c1)+len(cic1)}
在使用動態規劃後,程序將無單詞環而且不一樣時限定首尾的狀況的計算壓縮至了1s內,基本知足了要求。
第三階段:優化深度搜索
在進行動態規劃的優化以後,咱們發現,動態規劃雖然效率很高,可是並不能處理同時指定頭和尾的問題,因而咱們仿照動態規劃表達式的思想,對於咱們的深度優先搜索作了一步剪枝。具體的剪枝思想以下:
在搜索回退的時候,用一個數組,記錄下每一個字母距離其末尾的最大長度,或者最大單詞個數,當第二次搜索到這個字母節點時,直接比較當前長度,當前節點距離末尾的最大長度,若是前者比後者小,直接剪掉這個分支。保證了每條邊只搜索了一遍,極大的提升了深度優先搜索的效率。
性能測試:
上圖爲在無單詞環的狀況下進行的約九千單詞量的性能測試結果。由圖可知,在進行vector操做上的消耗較多。消耗最多的代碼是在addWord函數中將新單詞加入至有序單詞表的操做時採用了vector的insert函數。這一消耗僅出如今預處理的部分,在保證單詞表中的單詞是按照長度降序排列的同時還過濾了重複的單詞。該操做雖然帶來了必定的損耗,可是組織好的單詞表更易於計算過程的檢索,下降了檢索的複雜度,防止遞歸致使的消耗的放大。計算過程採用的動態規劃算法大大減少了該階段的消耗。
上圖爲在有單詞環的狀況下進行的性能測試。CPU的消耗主要出在遞歸調用的函數Dfs_solve1中。
Design by contract (DbC), also known as contract programming, programming by contract and design-by-contract programming, is an approach for designing software. It prescribes that software designers should define formal, precise and verifiable interface specifications for software components, which extend the ordinary definition of abstract data types with preconditions, postconditions and invariants.
以上是維基百科對契約式編程的釋義。有維基百科釋義可知,契約式編程中,每一個模塊有明確的契約關係,模塊互相調用的時候都有責任有義務向調用本身的模塊保證使用的正確性以及本身功能的正確性。
一、程序的總體設計更爲優秀
爲了符合契約式編程的核心思想,編程者必須在編程以前就要有個更好的總體設計以便於能更好的完成本身的契約,保證程序的正確性。爲了有更易於使用的接口,更正確的內部功能,必須有更清楚的設計,更簡單的設計。
二、提升系統可靠性,魯棒性
只要各個模塊都遵照契約,那麼必定程度上就大大的下降了模塊間耦合時之間的Bug。程序的魯棒性也獲得了很好的提高。
三、出色的文檔
契約乃是類特性的公用視圖中的固有成分,契約是值得信賴的文檔(運行時要檢查斷言,以保證制定的契約與程序的實際運行狀況一致)。
一、提升了編程的撰寫成本
爲了符合規範,並符合契約精神,編寫的時候必需要更加註意這些細節上的內容,增長了代碼編寫的成本。
二、須要有不少編程經驗
爲了真正的實現契約式編程,對編碼者的實際編程經驗也有較高的要求,須要編程着有較好的編程基礎以及必定的編程意識才能真正的完成契約式編程。
在撰寫類的時候,每一個類都單獨進行測試,封裝前確保了調用時的便宜性和功能的正確性。在封裝運算程序與GUI的時候也作到了 契約式編程,極大的方便了對接與測試。
筆者對工程中Core類的正確性以及封裝後的dll的正確性進行了測試
Core類測試集
1 TEST_CLASS(TEST) 2 { 3 public: 4 5 Core *CORE = NULL; 6 7 TEST_METHOD_INITIALIZE(initEnv) 8 { 9 CORE = new Core(); 10 } 11 12 TEST_METHOD_CLEANUP(cleanWordList) 13 { 14 delete CORE; 15 CORE = NULL; 16 } 17 18 TEST_METHOD(Test_1) // -w 19 { 20 string words[] = { 21 "ab", 22 "accccccccccccccccccccc", 23 "ad", 24 "bc", 25 "bd", 26 "cd", 27 }; 28 string ans[] = { 29 "ab", "bc", "cd" 30 }; 31 vector<string> *lines = new vector<string>(); 32 vector<string> *chain = new vector<string>(); 33 for(int i = 0; i < 6; i++) 34 { 35 lines->push_back(words[i]); 36 } 37 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 0, 0, false)); 38 Assert::AreEqual(size_t(3), chain->size()); 39 Assert::AreEqual(ans[0], (*chain)[0]); 40 Assert::AreEqual(ans[1], (*chain)[1]); 41 Assert::AreEqual(ans[2], (*chain)[2]); 42 delete lines; 43 delete chain; 44 } 45 46 TEST_METHOD(Test_2) // -c 47 { 48 string words[] = { 49 "ab", 50 "accccccccccccccccccccc", 51 "ad", 52 "bc", 53 "bd", 54 "cd", 55 }; 56 string ans[] = { 57 "accccccccccccccccccccc", "cd" 58 }; 59 vector<string> *lines = new vector<string>(); 60 vector<string> *chain = new vector<string>(); 61 for (int i = 0; i < 6; i++) 62 { 63 lines->push_back(words[i]); 64 } 65 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 0, 0, false)); 66 Assert::AreEqual(size_t(2), chain->size()); 67 Assert::AreEqual(ans[0], (*chain)[0]); 68 Assert::AreEqual(ans[1], (*chain)[1]); 69 delete lines; 70 delete chain; 71 } 72 73 TEST_METHOD(Test_3) // -w -h 74 { 75 string words[] = { 76 "ab", 77 "accccccccccccccccccccc", 78 "ad", 79 "bc", 80 "bdddd", 81 "cd", 82 }; 83 string ans[] = { 84 "bc", "cd" 85 }; 86 vector<string> *lines = new vector<string>(); 87 vector<string> *chain = new vector<string>(); 88 for (int i = 0; i < 6; i++) 89 { 90 lines->push_back(words[i]); 91 } 92 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 'b', 0, false)); 93 Assert::AreEqual(size_t(2), chain->size()); 94 Assert::AreEqual(ans[0], (*chain)[0]); 95 Assert::AreEqual(ans[1], (*chain)[1]); 96 delete lines; 97 delete chain; 98 } 99 100 TEST_METHOD(Test_4)// -c -h 101 { 102 string words[] = { 103 "ab", 104 "accccccccccccccccccccc", 105 "ad", 106 "bc", 107 "bdddd", 108 "cd", 109 "dd", 110 }; 111 string ans[] = { 112 "bdddd", "dd" 113 }; 114 vector<string> *lines = new vector<string>(); 115 vector<string> *chain = new vector<string>(); 116 for (int i = 0; i < 7; i++) 117 { 118 lines->push_back(words[i]); 119 } 120 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 'b', 0, false)); 121 Assert::AreEqual(size_t(2), chain->size()); 122 Assert::AreEqual(ans[0], (*chain)[0]); 123 Assert::AreEqual(ans[1], (*chain)[1]); 124 delete lines; 125 delete chain; 126 } 127 128 TEST_METHOD(Test_5)// -w -t 129 { 130 string words[] = { 131 "ab", 132 "accccccccccccccccccccc", 133 "ad", 134 "bc", 135 "bdddd", 136 "cd", 137 }; 138 string ans[] = { 139 "ab", "bc" 140 }; 141 vector<string> *lines = new vector<string>(); 142 vector<string> *chain = new vector<string>(); 143 for (int i = 0; i < 6; i++) 144 { 145 lines->push_back(words[i]); 146 } 147 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 0, 'c', false)); 148 Assert::AreEqual(size_t(2), chain->size()); 149 Assert::AreEqual(ans[0], (*chain)[0]); 150 Assert::AreEqual(ans[1], (*chain)[1]); 151 delete lines; 152 delete chain; 153 } 154 155 TEST_METHOD(Test_6)// -c -t 156 { 157 string words[] = { 158 "ab", 159 "accccccccccccccccccccc", 160 "ad", 161 "bc", 162 "bdddd", 163 "cd", 164 "cc" 165 }; 166 string ans[] = { 167 "accccccccccccccccccccc", "cc" 168 }; 169 vector<string> *lines = new vector<string>(); 170 vector<string> *chain = new vector<string>(); 171 for (int i = 0; i < 7; i++) 172 { 173 lines->push_back(words[i]); 174 } 175 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 0, 'c', false)); 176 Assert::AreEqual(size_t(2), chain->size()); 177 Assert::AreEqual(ans[0], (*chain)[0]); 178 Assert::AreEqual(ans[1], (*chain)[1]); 179 delete lines; 180 delete chain; 181 } 182 183 TEST_METHOD(Test_7)// -w -h -t 184 { 185 string words[] = { 186 "ab", 187 "accccccccccccccccccccc", 188 "ad", 189 "ae", 190 "bc", 191 "bdddd", 192 "be", 193 "cd", 194 "ce", 195 "de" 196 }; 197 string ans[] = { 198 "bc", "cd" 199 }; 200 vector<string> *lines = new vector<string>(); 201 vector<string> *chain = new vector<string>(); 202 for (int i = 0; i < 10; i++) 203 { 204 lines->push_back(words[i]); 205 } 206 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 'b', 'd', false)); 207 Assert::AreEqual(size_t(2), chain->size()); 208 Assert::AreEqual(ans[0], (*chain)[0]); 209 Assert::AreEqual(ans[1], (*chain)[1]); 210 delete lines; 211 delete chain; 212 } 213 214 TEST_METHOD(Test_8)// -c -h -t 215 { 216 string words[] = { 217 "ab", 218 "accccccccccccccccccccc", 219 "ad", 220 "ae", 221 "bc", 222 "bdddd", 223 "be", 224 "cd", 225 "ce", 226 "de", 227 "dd", 228 }; 229 string ans[] = { 230 "bdddd", "dd" 231 }; 232 vector<string> *lines = new vector<string>(); 233 vector<string> *chain = new vector<string>(); 234 for (int i = 0; i < 11; i++) 235 { 236 lines->push_back(words[i]); 237 } 238 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 'b', 'd', false)); 239 Assert::AreEqual(size_t(2), chain->size()); 240 Assert::AreEqual(ans[0], (*chain)[0]); 241 Assert::AreEqual(ans[1], (*chain)[1]); 242 delete lines; 243 delete chain; 244 } 245 246 TEST_METHOD(Test_9)// -w but have ring 247 { 248 string words[] = { 249 "ab", 250 "accccccccccccccccccccc", 251 "ad", 252 "ae", 253 "bc", 254 "bdddd", 255 "db", 256 "be", 257 "cd", 258 "ce", 259 "de" 260 }; 261 vector<string> *lines = new vector<string>(); 262 vector<string> *chain = new vector<string>(); 263 for (int i = 0; i < 11; i++) 264 { 265 lines->push_back(words[i]); 266 } 267 Assert::AreEqual(-2, CORE->gen_chain_word(*lines, *chain, 0, 0, false)); 268 delete lines; 269 delete chain; 270 } 271 272 TEST_METHOD(Test_10)// -c but have ring 273 { 274 string words[] = { 275 "ab", 276 "accccccccccccccccccccc", 277 "ad", 278 "ae", 279 "bc", 280 "bdddd", 281 "db", 282 "be", 283 "cd", 284 "ce", 285 "de" 286 }; 287 vector<string> *lines = new vector<string>(); 288 vector<string> *chain = new vector<string>(); 289 for (int i = 0; i < 11; i++) 290 { 291 lines->push_back(words[i]); 292 } 293 Assert::AreEqual(-2, CORE->gen_chain_char(*lines, *chain, 0, 0, false)); 294 delete lines; 295 delete chain; 296 } 297 298 TEST_METHOD(Test_11)// -w have self 299 { 300 string words[] = { 301 "ab", 302 "accccccccccccccccccccc", 303 "ad", 304 "ae", 305 "bb", 306 "bc", 307 "bdddd", 308 "be", 309 "cc", 310 "cd", 311 "ce", 312 "dd", 313 "de" 314 }; 315 string ans[] = { 316 "ab", "bb", "bc", "cc", "cd", "dd", "de" 317 }; 318 vector<string> *lines = new vector<string>(); 319 vector<string> *chain = new vector<string>(); 320 for (int i = 0; i < 13; i++) 321 { 322 lines->push_back(words[i]); 323 } 324 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 0, 0, false)); 325 Assert::AreEqual(size_t(7), chain->size()); 326 Assert::AreEqual(ans[0], (*chain)[0]); 327 Assert::AreEqual(ans[1], (*chain)[1]); 328 Assert::AreEqual(ans[2], (*chain)[2]); 329 Assert::AreEqual(ans[3], (*chain)[3]); 330 Assert::AreEqual(ans[4], (*chain)[4]); 331 Assert::AreEqual(ans[5], (*chain)[5]); 332 Assert::AreEqual(ans[6], (*chain)[6]); 333 delete lines; 334 delete chain; 335 } 336 337 TEST_METHOD(Test_12){// -c have self 338 string words[] = { 339 "ab", 340 "accccccccccccccccccccc", 341 "ad", 342 "ae", 343 "bb", 344 "bc", 345 "bdddd", 346 "be", 347 "cc", 348 "cd", 349 "ce", 350 "dd", 351 "de" 352 }; 353 string ans[] = { 354 "accccccccccccccccccccc", "cc", "cd", "dd", "de" 355 }; 356 vector<string> *lines = new vector<string>(); 357 vector<string> *chain = new vector<string>(); 358 for (int i = 0; i < 13; i++) 359 { 360 lines->push_back(words[i]); 361 } 362 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 0, 0, false)); 363 Assert::AreEqual(size_t(5), chain->size()); 364 Assert::AreEqual(ans[0], (*chain)[0]); 365 Assert::AreEqual(ans[1], (*chain)[1]); 366 Assert::AreEqual(ans[2], (*chain)[2]); 367 Assert::AreEqual(ans[3], (*chain)[3]); 368 Assert::AreEqual(ans[4], (*chain)[4]); 369 delete lines; 370 delete chain; 371 } 372 373 TEST_METHOD(Test_13)// -w -r 374 { 375 string words[] = { 376 "ab", "aaaaabbbbbccccc", "aaaaaddddd", 377 "bc", 378 "cb", "cd", 379 }; 380 string ans[] = { 381 "aaaaabbbbbccccc", "cb", "bc", "cd" 382 }; 383 vector<string> *lines = new vector<string>(); 384 vector<string> *chain = new vector<string>(); 385 for (int i = 0; i < 6; i++) 386 { 387 lines->push_back(words[i]); 388 } 389 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 0, 0, true)); 390 Assert::AreEqual(size_t(4), chain->size()); 391 Assert::AreEqual(ans[0], (*chain)[0]); 392 Assert::AreEqual(ans[1], (*chain)[1]); 393 Assert::AreEqual(ans[2], (*chain)[2]); 394 Assert::AreEqual(ans[3], (*chain)[3]); 395 delete lines; 396 delete chain; 397 } 398 399 TEST_METHOD(Test_14) {// -c -r 400 string words[] = { 401 "ab", "aaaccc", "aaaaabbbbbcccccddddd", 402 "bc", 403 "cb", "cd", 404 "dd", 405 }; 406 string ans[] = { 407 "aaaaabbbbbcccccddddd", "dd" 408 }; 409 vector<string> *lines = new vector<string>(); 410 vector<string> *chain = new vector<string>(); 411 for (int i = 0; i < 7; i++) 412 { 413 lines->push_back(words[i]); 414 } 415 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 0, 0, true)); 416 Assert::AreEqual(size_t(2), chain->size()); 417 Assert::AreEqual(ans[0], (*chain)[0]); 418 Assert::AreEqual(ans[1], (*chain)[1]); 419 delete lines; 420 delete chain; 421 } 422 423 TEST_METHOD(Test_15) {// -w -r -h -t 424 string words[] = { 425 "ab", 426 "bccccccccccccccccccccccccccc", "bd", 427 "cd", 428 "da", "dc", 429 }; 430 string ans[] = { 431 "bd", "dc", "cd", "da" 432 }; 433 vector<string> *lines = new vector<string>(); 434 vector<string> *chain = new vector<string>(); 435 for (int i = 0; i < 6; i++) 436 { 437 lines->push_back(words[i]); 438 } 439 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 'b', 'a', true)); 440 Assert::AreEqual(size_t(4), chain->size()); 441 Assert::AreEqual(ans[0], (*chain)[0]); 442 Assert::AreEqual(ans[1], (*chain)[1]); 443 Assert::AreEqual(ans[2], (*chain)[2]); 444 Assert::AreEqual(ans[3], (*chain)[3]); 445 delete lines; 446 delete chain; 447 } 448 449 TEST_METHOD(Test_16) {// -c -r -h 450 string words[] = { 451 "ab", 452 "bccccccccccccccccccccccccccc", "bd", 453 "cd", 454 "da", "dc", 455 }; 456 string ans[] = { 457 "bccccccccccccccccccccccccccc","cd", "da" 458 }; 459 vector<string> *lines = new vector<string>(); 460 vector<string> *chain = new vector<string>(); 461 for (int i = 0; i < 6; i++) 462 { 463 lines->push_back(words[i]); 464 } 465 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 'b', 'a', true)); 466 Assert::AreEqual(size_t(3), chain->size()); 467 Assert::AreEqual(ans[0], (*chain)[0]); 468 Assert::AreEqual(ans[1], (*chain)[1]); 469 Assert::AreEqual(ans[2], (*chain)[2]); 470 delete lines; 471 delete chain; 472 }
拓撲排序測試
1 TEST_METHOD(TEST_TopoSort_1) 2 { 3 string str_list[] = { 4 "aa", "abc" , "cbd", "ddd", "da" 5 }; 6 for (int i = 0; i < 5; i++) 7 { 8 WORDLIST->parseString(str_list[i]); 9 } 10 dpSolve = new DPSolve(WORDLIST, 'w'); 11 Assert::AreEqual(false, dpSolve->topoSort()); 12 } 13 14 TEST_METHOD(TEST_TopoSort_2) 15 { 16 string str_list[] = { 17 "aa", "abc" , "cbd", "ddd", "db" 18 }; 19 for (int i = 0; i < 5; i++) 20 { 21 WORDLIST->parseString(str_list[i]); 22 } 23 dpSolve = new DPSolve(WORDLIST, 'w'); 24 Assert::AreEqual(true, dpSolve->topoSort()); 25 }
dll測試
1 TEST_METHOD(Test_1) // -w 2 { 3 char* words[] = { 4 "ab", 5 "accccccccccccccccccccc", 6 "ad", 7 "bc", 8 "bd", 9 "cd", 10 }; 11 char* chain[100]; 12 char* ans[] = { 13 "ab", "bc", "cd" 14 }; 15 Assert::AreEqual(3, gen_chain_word(words, 6, chain, 0, 0, false)); 16 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 17 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 18 Assert::AreEqual(0, strcmp(chain[2], ans[2])); 19 } 20 21 TEST_METHOD(Test_2) // -c 22 { 23 char* words[] = { 24 "ab", 25 "accccccccccccccccccccc", 26 "ad", 27 "bc", 28 "bd", 29 "cd", 30 }; 31 char* chain[100]; 32 char* ans[] = { 33 "accccccccccccccccccccc", "cd" 34 }; 35 Assert::AreEqual(2, gen_chain_char(words, 6, chain, 0, 0, false)); 36 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 37 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 38 } 39 40 TEST_METHOD(Test_3) // -w -h 41 { 42 char* words[] = { 43 "ab", 44 "accccccccccccccccccccc", 45 "ad", 46 "bc", 47 "bdddd", 48 "cd", 49 }; 50 char* chain[100]; 51 char* ans[] = { 52 "bc", "cd" 53 }; 54 Assert::AreEqual(2, gen_chain_word(words, 6, chain, 'b', 0, false)); 55 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 56 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 57 } 58 59 TEST_METHOD(Test_4) // -c -h 60 { 61 char* words[] = { 62 "ab", 63 "accccccccccccccccccccc", 64 "ad", 65 "bc", 66 "bdddd", 67 "cd", 68 "dd", 69 }; 70 char* chain[100]; 71 char* ans[] = { 72 "bdddd", "dd" 73 }; 74 Assert::AreEqual(2, gen_chain_char(words, 7, chain, 'b', 0, false)); 75 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 76 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 77 } 78 79 TEST_METHOD(Test_5) // -w -t 80 { 81 char* words[] = { 82 "ab", 83 "accccccccccccccccccccc", 84 "ad", 85 "bc", 86 "bdddd", 87 "cd", 88 }; 89 char* chain[100]; 90 char* ans[] = { 91 "ab", "bc" 92 }; 93 Assert::AreEqual(2, gen_chain_word(words, 6, chain, 0, 'c', false)); 94 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 95 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 96 } 97 98 TEST_METHOD(Test_6) // -c -t 99 { 100 char* words[] = { 101 "ab", 102 "accccccccccccccccccccc", 103 "ad", 104 "bc", 105 "bdddd", 106 "cd", 107 "cc" 108 }; 109 char* chain[100]; 110 char* ans[] = { 111 "accccccccccccccccccccc", "cc" 112 }; 113 Assert::AreEqual(2, gen_chain_char(words, 7, chain, 0, 'c', false)); 114 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 115 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 116 } 117 118 TEST_METHOD(Test_7)// -w -h -t 119 { 120 char* words[] = { 121 "ab", 122 "accccccccccccccccccccc", 123 "ad", 124 "ae", 125 "bc", 126 "bdddd", 127 "be", 128 "cd", 129 "ce", 130 "de" 131 }; 132 char* chain[100]; 133 char* ans[] = { 134 "bc", "cd" 135 }; 136 Assert::AreEqual(2, gen_chain_word(words, 10, chain, 'b', 'd', false)); 137 138 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 139 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 140 } 141 142 TEST_METHOD(Test_8)// -c -h -t 143 { 144 char* words[] = { 145 "ab", 146 "accccccccccccccccccccc", 147 "ad", 148 "ae", 149 "bc", 150 "bdddd", 151 "be", 152 "cd", 153 "ce", 154 "de", 155 "dd", 156 }; 157 char* chain[100]; 158 char* ans[] = { 159 "bdddd", "dd" 160 }; 161 Assert::AreEqual(2, gen_chain_char(words, 11, chain, 'b', 'd', false)); 162 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 163 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 164 } 165 166 TEST_METHOD(Test_9)// -w but have ring 167 { 168 char* words[] = { 169 "ab", 170 "accccccccccccccccccccc", 171 "ad", 172 "ae", 173 "bc", 174 "bdddd", 175 "db", 176 "be", 177 "cd", 178 "ce", 179 "de" 180 }; 181 char* chain[100]; 182 Assert::AreEqual(-4, gen_chain_word(words, 11, chain, 0, 0, false)); 183 } 184 185 TEST_METHOD(Test_10)// -c but have ring 186 { 187 char* words[] = { 188 "ab", 189 "accccccccccccccccccccc", 190 "ad", 191 "ae", 192 "bc", 193 "bdddd", 194 "db", 195 "be", 196 "cd", 197 "ce", 198 "de" 199 }; 200 char* chain[100]; 201 Assert::AreEqual(-4, gen_chain_char(words, 11, chain, 0, 0, false)); 202 } 203 204 TEST_METHOD(Test_11)// -w have self 205 { 206 char* words[] = { 207 "ab", 208 "accccccccccccccccccccc", 209 "ad", 210 "ae", 211 "bb", 212 "bc", 213 "bdddd", 214 "be", 215 "cc", 216 "cd", 217 "ce", 218 "dd", 219 "de" 220 }; 221 char* chain[100]; 222 char* ans[] = { 223 "ab", "bb", "bc", "cc", "cd", "dd", "de" 224 }; 225 Assert::AreEqual(7, gen_chain_word(words, 13, chain, 0, 0, false)); 226 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 227 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 228 Assert::AreEqual(0, strcmp(chain[2], ans[2])); 229 Assert::AreEqual(0, strcmp(chain[3], ans[3])); 230 Assert::AreEqual(0, strcmp(chain[4], ans[4])); 231 Assert::AreEqual(0, strcmp(chain[5], ans[5])); 232 Assert::AreEqual(0, strcmp(chain[6], ans[6])); 233 } 234 235 TEST_METHOD(Test_12) {// -c have self 236 char* words[] = { 237 "ab", 238 "accccccccccccccccccccc", 239 "ad", 240 "ae", 241 "bb", 242 "bc", 243 "bdddd", 244 "be", 245 "cc", 246 "cd", 247 "ce", 248 "dd", 249 "de" 250 }; 251 char* chain[100]; 252 char* ans[] = { 253 "accccccccccccccccccccc", "cc", "cd", "dd", "de" 254 }; 255 Assert::AreEqual(5, gen_chain_char(words, 13, chain, 0, 0, false)); 256 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 257 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 258 Assert::AreEqual(0, strcmp(chain[2], ans[2])); 259 Assert::AreEqual(0, strcmp(chain[3], ans[3])); 260 Assert::AreEqual(0, strcmp(chain[4], ans[4])); 261 } 262 263 TEST_METHOD(Test_13)// -w -r 264 { 265 char* words[] = { 266 "ab", "aaaaabbbbbccccc", "aaaaaddddd", 267 "bc", 268 "cb", "cd", 269 }; 270 char* chain[100]; 271 char* ans[] = { 272 "aaaaabbbbbccccc", "cb", "bc", "cd" 273 }; 274 Assert::AreEqual(4, gen_chain_word(words, 6, chain, 0, 0, true)); 275 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 276 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 277 Assert::AreEqual(0, strcmp(chain[2], ans[2])); 278 Assert::AreEqual(0, strcmp(chain[3], ans[3])); 279 } 280 281 TEST_METHOD(Test_14) {// -c -r 282 char* words[] = { 283 "ab", "aaaccc", "aaaaabbbbbcccccddddd", 284 "bc", 285 "cb", "cd", 286 "dd", 287 }; 288 char* ans[] = { 289 "aaaaabbbbbcccccddddd", "dd" 290 }; 291 char* chain[100]; 292 Assert::AreEqual(2, gen_chain_char(words, 7, chain, 0, 0, true)); 293 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 294 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 295 } 296 297 TEST_METHOD(Test_15) {// -w -r -h -t 298 char* words[] = { 299 "ab", 300 "bccccccccccccccccccccccccccc", "bd", 301 "cd", 302 "da", "dc", 303 }; 304 char* ans[] = { 305 "bd", "dc", "cd", "da" 306 }; 307 char* chain[100]; 308 Assert::AreEqual(4, gen_chain_word(words, 6, chain, 'b', 'a', true)); 309 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 310 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 311 Assert::AreEqual(0, strcmp(chain[2], ans[2])); 312 Assert::AreEqual(0, strcmp(chain[3], ans[3])); 313 } 314 315 TEST_METHOD(Test_16) {// -c -r -h 316 char* words[] = { 317 "ab", 318 "bccccccccccccccccccccccccccc", "bd", 319 "cd", 320 "da", "dc", 321 }; 322 char* ans[] = { 323 "bccccccccccccccccccccccccccc","cd", "da" 324 }; 325 char* chain[100]; 326 Assert::AreEqual(3, gen_chain_char(words, 6, chain, 'b', 'a', true)); 327 Assert::AreEqual(0, strcmp(chain[0], ans[0])); 328 Assert::AreEqual(0, strcmp(chain[1], ans[1])); 329 Assert::AreEqual(0, strcmp(chain[2], ans[2])); 330 }
如下是測試時代碼覆蓋率及測試結果。
異常種類:
輸入輸出單詞表有效性
參數(head、tail)有效性
無環狀況搜索到環
未搜索到單詞鏈
異常測試:
輸入輸出單詞表有效性測試
1 TEST_METHOD(Test_1) 2 { 3 char* words[] = { 4 NULL, 5 NULL, 6 "ad", 7 "bc", 8 "bd", 9 "cd", 10 }; 11 char* chain[100]; 12 Assert::AreEqual(-3, gen_chain_word(words, 6, chain, 0, 0, false)); 13 }
參數有效性測試
1 TEST_METHOD(Test_2) 2 { 3 char* words[] = { 4 "ab", 5 "accccccccccccccccccccc", 6 "ad", 7 "bc", 8 "bd", 9 "cd", 10 }; 11 char* chain[100]; 12 Assert::AreEqual(-1, gen_chain_word(words, 6, chain, '-', 0, false)); 13 } 14 15 TEST_METHOD(Test_3) 16 { 17 char* words[] = { 18 "ab", 19 "accccccccccccccccccccc", 20 "ad", 21 "bc", 22 "bd", 23 "cd", 24 }; 25 char* chain[100]; 26 Assert::AreEqual(-2, gen_chain_word(words, 6, chain, 0, '-', false)); 27 }
環識別測試
1 TEST_METHOD(Test_6) 2 { 3 char* words[] = { 4 "ab", 5 "accccccccccccccccccccc", 6 "ba", 7 }; 8 char* chain[100]; 9 Assert::AreEqual(-4, gen_chain_word(words, 3, chain, 0, 0, false)); 10 }
未搜索到單詞鏈測試
1 TEST_METHOD(Test_4) 2 { 3 char* words[] = { 4 "ab", 5 "accccccccccccccccccccc", 6 "ad", 7 }; 8 char* chain[100]; 9 Assert::AreEqual(-5, gen_chain_word(words, 3, chain, 0, 0, false)); 10 }
界面模塊設計主要採用C++的 QT模塊,利用QT creator 先設計好主要的GUI界面以後,導出代碼,而後針對每一個控件編寫相應的響應函數。GUI 實在64位的編譯環境下編寫,主要支持功能時直接輸入框輸入單詞,和用戶交互式的導入文本文件,也支持將程序運行的結果導出到用戶指定文件中。
模塊主要界面以下:
其中主要的功能函數綁定在openfile writefile 以及 run 三個Button 上,界面代碼以下:
1 void gui(QMainWindow *MainWindow) 2 { 3 if (MainWindow->objectName().isEmpty()) 4 MainWindow->setObjectName(QStringLiteral("MainWindow")); 5 MainWindow->resize(661, 397); 6 centralWidget = new QWidget(MainWindow); 7 centralWidget->setObjectName(QStringLiteral("centralWidget")); 8 //centralWidget = MainWindow; 9 textBrowser = new QTextBrowser(centralWidget); 10 textBrowser->setObjectName(QStringLiteral("textBrowser")); 11 textBrowser->setGeometry(QRect(300, 50, 201, 221)); 12 textBrowser_2 = new QTextEdit(centralWidget); 13 textBrowser_2->setObjectName(QStringLiteral("textBrowser_2")); 14 textBrowser_2->setGeometry(QRect(10, 50, 201, 221)); 15 checkBox = new QCheckBox(centralWidget); 16 checkBox->setObjectName(QStringLiteral("checkBox")); 17 checkBox->setGeometry(QRect(540, 40, 71, 16)); 18 checkBox_2 = new QCheckBox(centralWidget); 19 checkBox_2->setObjectName(QStringLiteral("checkBox_2")); 20 checkBox_2->setGeometry(QRect(540, 60, 71, 16)); 21 checkBox_3 = new QCheckBox(centralWidget); 22 checkBox_3->setObjectName(QStringLiteral("checkBox_3")); 23 checkBox_3->setGeometry(QRect(540, 80, 71, 16)); 24 checkBox_4 = new QCheckBox(centralWidget); 25 checkBox_4->setObjectName(QStringLiteral("checkBox_4")); 26 checkBox_4->setGeometry(QRect(540, 100, 71, 16)); 27 checkBox_5 = new QCheckBox(centralWidget); 28 checkBox_5->setObjectName(QStringLiteral("checkBox_5")); 29 checkBox_5->setGeometry(QRect(540, 20, 71, 16)); 30 textEdit = new QLineEdit(centralWidget); 31 textEdit->setObjectName(QStringLiteral("textEdit")); 32 textEdit->setGeometry(QRect(540, 140, 30, 30)); 33 textEdit_2 = new QLineEdit(centralWidget); 34 textEdit_2->setObjectName(QStringLiteral("textEdit_2")); 35 textEdit_2->setGeometry(QRect(580, 140, 30, 30)); 36 label = new QLabel(centralWidget); 37 label->setObjectName(QStringLiteral("label")); 38 label->setGeometry(QRect(540, 120, 31, 20)); 39 label_2 = new QLabel(centralWidget); 40 label_2->setObjectName(QStringLiteral("label_2")); 41 label_2->setGeometry(QRect(580, 120, 31, 20)); 42 pushButton = new QPushButton(centralWidget); 43 pushButton->setObjectName(QStringLiteral("pushButton")); 44 pushButton->setGeometry(QRect(70, 10, 75, 23)); 45 pushButton_2 = new QPushButton(centralWidget); 46 pushButton_2->setObjectName(QStringLiteral("pushButton_2")); 47 pushButton_2->setGeometry(QRect(360, 10, 75, 23)); 48 pushButton_3 = new QPushButton(centralWidget); 49 pushButton_3->setObjectName(QStringLiteral("pushButton_3")); 50 pushButton_3->setGeometry(QRect(220, 130, 75, 23)); 51 MainWindow->setCentralWidget(centralWidget); 52 menuBar = new QMenuBar(MainWindow); 53 menuBar->setObjectName(QStringLiteral("menuBar")); 54 menuBar->setGeometry(QRect(0, 0, 661, 23)); 55 MainWindow->setMenuBar(menuBar); 56 mainToolBar = new QToolBar(MainWindow); 57 mainToolBar->setObjectName(QStringLiteral("mainToolBar")); 58 MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar); 59 statusBar = new QStatusBar(MainWindow); 60 statusBar->setObjectName(QStringLiteral("statusBar")); 61 MainWindow->setStatusBar(statusBar); 62 retranslateUi(MainWindow); 63 64 QMetaObject::connectSlotsByName(MainWindow); 65 } // setupUi
該 button 綁定了導入輸入文件的函數,能夠方便讓用戶直接導入本身的輸入數據,代碼實現以下:
1 void MainWindow::openfile() 2 { 3 4 QString fileName = QFileDialog::getOpenFileName(this,tr("choose log"),"",tr("TXT(*.txt)")); 5 if (fileName.isEmpty()) 6 return; 7 QFile file(fileName); 8 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) 9 { 10 while (!file.atEnd()) 11 { 12 13 QByteArray line = file.readLine(); 14 QString str(line); 15 16 //qDebug() << str;; 17 this->textBrowser_2->insertPlainText(str); 18 } 19 20 file.close(); 21 } 22 23 }
該 button 綁定了導入結果數據的函數,能夠方便讓用戶直接導出函數的運行結果,代碼實現以下:
1 void MainWindow::writefile() 2 { 3 4 QString fileName = QFileDialog::getOpenFileName(this,tr("choose log"),"",tr("TXT(*.txt)")); 5 if (fileName.isEmpty()) 6 return; 7 QFile file(fileName); 8 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) 9 { 10 while (!file.atEnd()) 11 { 12 13 QByteArray line = file.readLine(); 14 QString str(line); 15 16 //qDebug() << str;; 17 this->textBrowser_2->insertPlainText(str); 18 } 19 20 file.close(); 21 } 22 23 }
該button綁定的函數調用了Core.dll中的函數,實現了對數據的處理與計算。代碼以下:
1 void MainWindow::run() 2 { 3 QLibrary mylib("Core.dll"); 4 mylib.load(); 5 //加載動態庫 6 if (!mylib.isLoaded()) 7 { 8 qDebug()<<QString("Load Oracle oci.dll failed!\n"); 9 return ; 10 } 11 p_gen_chain_word get_chain_word=(p_gen_chain_word)mylib.resolve("gen_chain_word"); 12 p_gen_chain_char get_chain_char=(p_gen_chain_char)mylib.resolve("gen_chain_char"); 13 char head = '\0',end = '\0'; 14 char* words[10000]; 15 char* result[10000]; 16 bool b_w = this->checkBox->isChecked()==true; 17 bool b_c = this->checkBox_2->isChecked()==true; 18 bool b_h = this->checkBox_3->isChecked()==true; 19 bool b_t = this->checkBox_4->isChecked()==true; 20 bool b_r = this->checkBox_5->isChecked()==true; 21 if(b_w && b_c) 22 { 23 QMessageBox:: information(NULL,"Error","can't choose w and c at the same time"); 24 return; 25 } 26 if(!b_w && !b_c) 27 { 28 QMessageBox:: information(NULL,"Error","need a w or cs"); 29 return; 30 } 31 if(b_h) 32 { 33 QByteArray head_text = this->textEdit->text().toLower().toLatin1(); 34 head = head_text.data()[0]; 35 if(!(head>='a' && head <='z')) 36 { 37 QMessageBox:: information(NULL,"Error","head must in a-z"); 38 return; 39 } 40 41 } 42 if(b_t) 43 { 44 QByteArray head_text = this->textEdit_2->text().toLower().toLatin1(); 45 end = head_text.data()[0]; 46 if(!(head>='a' && head <='z')) 47 { 48 QMessageBox:: information(NULL,"Error","tail must in a-z"); 49 return; 50 } 51 52 } 53 54 QStringList text = this->textBrowser_2->toPlainText().split("\n"); 55 int len = 0; 56 int word_num = String2Char(text,words); 57 if(b_w) 58 { 59 len = get_chain_word(words,word_num,result,head,end,b_r); 60 } 61 if(b_c) 62 { 63 len = get_chain_char(words,word_num,result,head,end,b_r); 64 } 65 if(len<=1) 66 { 67 if(len == -4) 68 { 69 QMessageBox:: information(NULL,"Error","shouldn't have circles"); 70 return; 71 } 72 if(len == -5) 73 { 74 QMessageBox:: information(NULL,"Error","Chain don't exist"); 75 return; 76 } 77 QMessageBox:: information(NULL,"Error","unkown error! please input valid data"); 78 return; 79 } 80 qDebug()<<len; 81 int i; 82 this->textBrowser->clear(); 83 for(i = 0;i<len;i++) 84 { 85 string a(result[i]); 86 this->textBrowser->append(QString::fromStdString(a)); 87 qDebug()<<QString::fromStdString(a); 88 } 89 }
筆者小組同其餘小組(16061161-15231112組和16061093-16061155組)進行了計算模塊dll的交換。因爲兩個小組在項目開始前就對接口部分進行了討論,在接口各參數、返回值以及功能上達成了共識,即計算接口設計部分所述。因爲完成全部模塊的設計及dll打包後,筆者在本小組的測試程序以及GUI上對dll進行了導入測試,在進入與其餘小組對接階段時並未遇到嚴重BUG,但在這過程當中也遇到了一些小問題。
打包dll和GUI模塊所支持處理器不一樣。 在最初打包dll時未注意X86和X64以及Debug和Release版本間的區別,打包出錯誤版本的dll,致使GUI沒法導入dll。在複覈了版本後就解決了這一問題。
異常處理問題。 筆者小組採用Qt Creater進行GUI部分的開發,然後端進行Visual Studio進行開發。前者對於dll拋出異常的支持較差,容易致使程序出錯。在採用返回值返回錯誤信息的方式後解決了這一問題。
在結對以前,筆者和結對夥伴就已經認識,但從未在程序開發上進行合做。本次結對編程應當是小組兩人第一次合做開發。如下是按照項目開發的里程碑來總覽筆者小組開發的歷程。
啓動題目 在結對題目剛出來時,咱們很快就在一塊兒對需求進行了討論,很快就列出了最初的項目設計以及日程計劃,開始了項目的推動。因爲其餘課程以及實驗室任務等緣由,咱們並無不少公共的時間進行結對開發,僅有天天晚上用大約6小時左右的時間一同編程。
完成第一版 在項目啓動後約兩天,咱們就按照最初的設計(設計見性能改進部分)實現了程序的基本功能。在實現的過程當中,筆者按照單元測試的編寫要求,編寫並進行了單元測試,完成了初版的測試集,供後期迴歸測試使用。
優化算法 因爲最初的設計的時間複雜度較高,咱們在完成第一版的測試後便進入了算法的改進和優化的階段。筆者將部分的功能改成使用動態規劃算法實現,並根據搜索單詞鏈的要求設計了不一樣的遞推式。筆者的搭檔將第一版的深度搜索進行了優化以補充動態規劃未涉及的功能。通過了約4天,咱們基本完成了算法的優化,開始了新測試的編寫以及進行迴歸測試。
GUI開發和核心代碼封裝 在算法優化的後半階段,咱們開始了GUI部分的同步開發以及計算模塊的封裝。這一部分是咱們整個開發過程當中最爲艱難的階段。咱們在Qt環境的配置、dll的打包及使用上遇到了不少困難。主要在於dll相似於黑盒,咱們在測試其是否打包成功並加載入Qt是耗費了不少時間。
終版完成 最終通過了兩週的結對編程,筆者和搭檔較好的完成了最長單詞鏈的程序。在這過程當中,因爲是第一次結對編程前期的效率並不高。直到進入了優化階段,咱們在逐漸找到告終對編程的節奏,最終使用了約2000分鐘完成了項目。
通過長達兩週的結對編程,結合《構建之法》中對結對編程的描述以及這兩週的親身經歷,筆者對於結對編程的優缺點有了如下的感想。
更容易定位Bug 結對編程過程當中,兩我的共同看一份代碼,極大的解決了兩我的分工合做致使的代碼bug 定位困難的問題,兩我的在一塊兒編程,總有一我的能夠快速的定位到bug 的位置。
能夠設計出更好的方法 俗話說三個臭皮匠,頂個諸葛亮,在結對編程中,兩我的一塊兒思考算法,總結出的解決問題的方法每每會比一我的想出來的更嚴謹也更高效。讓程序的總體性能上也獲得了提高。
溝通方便 結對編程,兩我的坐在一塊兒編程,溝通起來也是十分的方便,不只很好的避免了兩我的在溝通上容易產生的誤解,也極大的減小了溝通所用的時間,很大程度上節省了沒必要要的爭執,與誤解致使的時間上的狼浪費。
進度會被減慢 由於結對開發不是兩我的的並行開發,因此必定程度上的減慢了項目總體推動的效率,致使整個工做週期被大大的延長。
通過了兩週的合做,筆者對本身和隊友在結對編程中各自的亮點和不足進行了一下總結。
隊員 | 優勢 | 不足 |
---|---|---|
筆者 | 1.吃苦耐勞 2.善於接受新知識 3.積極溝通 | 不善於撰寫報告,以及進行程序測試 |
隊友 | 1.代碼編寫規範 2.善於寫測試用例 3.善於封裝程序 |