本次做業的需求能夠分紅基本的功能實現和大規模數據下程序的健壯性,以及少許的異常處理能力,也就是說咱們能夠經過通常功能測試和壓力測試和少許的魯棒性測試來進行測試。html
程序的測試結果首先參考了2017BUAA軟工助教 我的項目測試結果
測試-c的結果以下圖:linux
NumberID | -c 1 | -c 5 | -c 100 | -c 500 | -c 1000 | -c 50000 | -c 1000000 |
---|---|---|---|---|---|---|---|
15061104 | 0.9 | 0.117 | 0.218 | 0.76 | 1.326 | 60.102 | -8 |
測試-s的結果以下圖:ios
NumberID | -s 1.txt | -s 5.txt | -s 100.txt | -s 500.txt | -s 1000.txt | -s 50000.txt | -s 1000000.txt |
---|---|---|---|---|---|---|---|
15061104 | 0.148 | 0.2 | 2.637 | 12.7 | 25.165 | -2 | -4 |
接下來分別說明這些測試的結果。git
suduku.exe -c 1000000
等待10分鐘無果。github
樣例 | 語句 | 說明 | 預期結果 | 實際結果 |
---|---|---|---|---|
case1 | sudoku.exe -c asd | 參數非法 | 退出並報錯 | 報錯並退出 |
case2 | sudoku.exe -c 0 | 邊界值 | 退出並報錯,或者sudoku.txt爲空 | 報錯並退出 |
case3 | sudoku.exe -c -1 | 參數越界 | 退出並報錯 | 報錯並退出 |
case4 | sudoku.exe -c 10000000 | 參數越界 | 退出並報錯 | 報錯並退出 |
case5 | sudoku.exe -s nonexist.txt | 文件不存在 | 退出並報錯 | 退出 |
case6 | sudoku.exe -s nosolution.txt | 文件中數獨不可解 | 退出並報錯 | sudoku.txt中生成全0數獨 |
case7 | sudoku.exe -s | 參數不夠 | 退出並報錯 | 報錯並退出 |
根據1.1中的測試結果可知,程序在考慮設計上有些欠穩當。算法
從代碼的:層次結構,註釋的詳盡程度,註釋的易讀程度,變量的命名清晰度來分析。數據庫
層次結構
優勢:做者使用的是DLX算法,代碼大部分採用了OO的風格,代碼中大體包括DLXNode,DLXGenerator,DLXSolver,SudokuLoader,SudokuSolver,這些類的劃分比較清晰易懂,從main函數開始的層次結構也比較清楚。
缺點:Issue1(1)main.cpp中的幾個函數solvePuzzle、createSudoku等頗有面向過程的風格,很讓人困惑,也許更好的方法是把這些函數封裝到相關類的方法中。(2)程序的輸出由類SudokuLoader來實現,這個功能明顯和這個類的命名有衝突,也許能夠新建一個SudokuOutput類來處理。設計模式
註釋的詳盡程度
優勢:程序對大部分方法都有簡略的說明,在一些具體的算法步驟上也有說明,有必定的可讀性。
缺點:程序對類的說明較少,也許能夠對每一個類加一個簡要的註釋來講明其職責、可變性等。數組
註釋的易讀程度
較好,沒有生僻詞。雖然方法只有說明沒有具體的例子,但由於本次做業比較簡單,因此不須要也能夠讀懂。網絡
變量的命名清晰度
比較清晰,基本能從名字中瞭解到變量的功能。
總結
整體來講,代碼可讀性較高,但在結構設計和類的功能劃分上仍有部分細節有些混亂。
可維護性主要是指代碼是否能適應各類各樣的變化,此次做業結構比較簡單,因此整體來講問題不大。
不過測試代碼中用到了itoa函數,這個函數在linux中不可用,會致使程序的可維護性下降。見Issue5
除了一些冗餘的代碼,基本能夠所有覆蓋,冗餘代碼的說明在2.5節。
沒有特定的設計模式。
存在。Issue3
在SudokuLoader::writeToFile函數中使用了硬編碼:
char content[19 * 9 + 2];
代碼自己沒有影響,可是測試代碼中含有itoa會影響移植到linux以後的測試。
基本沒有,因爲使用了DLX,其中的一些基本操做和數據結構須要從新定義。
有:
void solveWithAllAnswers(DLXNode *listHead, vector<int>& tempSolution, vector<vector<int>>& lastSolution, int depth);
這個方法的定義和代碼均可以刪除。Issue4
代碼基本有統一的風格,問題已經在以前闡述過。
內部的異常處理在1.1中闡述過。
對於外部操做,在用fstream來操做文件的時候,有以下代碼:
if (strcmp(argv[1], "-s") == 0) { //Solve puzzle from file fstream puzzleFile; puzzleFile.open(argv[2], ios::in); solvePuzzle(puzzleFile); puzzleFile.close(); } else if (strcmp(argv[1], "-c") == 0 && atoi(argv[2]) > 0 && atoi(argv[2]) <= sudokuMaximum) { //Create puzzle file fstream sudokuFile; sudokuFile.open("sudoku.txt", ios::out); createSudoku(sudokuFile, atoi(argv[2])); sudokuFile.close(); } else { reportError(); }
這裏在打開文件以後沒有檢查文件是否打開,建議使用is_open()方法來檢查是否打開。
沒有
代碼中有3次用new關鍵字進行的資源的申請,下面是其中一處:
SudokuSolver solver = SudokuSolver(); DLXNode* listHead = new DLXNode(); vector<int> answer;
這三處申請都沒有釋放。
考慮到申請的不是數組,而且是有限次申請,因此致使資源泄露的可能性比較小。
但仍是建議應該在程序結束以後釋放相應的資源。
因爲是有限的new,因此優化的空間比較小。
沒有,DLXNode中定義的成員都有明確的使用目的。
在1.1中咱們看到,代碼的效能比較不盡人意,生成50000個數獨就要60秒,而解50000個數獨的時候沒有生成相應的文件。
沒有,程序的熱路徑都在DLX的遞歸調用上。
會超時,判斷應該是算法遞歸層數加深變得沒法處理,應該進一步優化算法。
1.3中已經有過闡述,整體來講比較易讀,推薦對每一個類進行簡單的功能和性質說明。
做者基於簡單的數據規模測試了3個核心的功能函數,即和生成和求解數獨有關的3個函數。
但這樣測試的粒度過大,會致使發生錯誤的時候定位難,同時測試中也沒有包括一些異常檢測和壓力測試。
建議添加相應的測試,並將核心方法分解成更細粒度的方法進行測試。
(1)是否添加copyright
(2)在include .h頭文件的時候應該聲明相應的路徑
(3)建議使用using-declarations,舉例來講就是,把cout替換成std::cout。
(4)用int64而不是long,long是c中的類型
(5)//和註釋之間應該有一個空格
(6)建議採用K&R風格的大括號,個人代碼中大部分使用這個風格,只有定義函數的時候會把包圍函數的左大括號換行,cpplint中也只是使用了'almost'這個詞來限定這條規則
(7)用空格來代替tab
(8)’,‘以後應該空格
(9)行結束以前有多餘的空格
(10)else放在if的有大括號以後
(11)代碼塊結束以後有冗餘的空行
(1)添加copyright
加做者仍是比較有必要的,畢竟是本身的勞動成果。
(2)聲明.h文件的時候應該聲明相應的路徑
這條沒想到過,不過思考了一下確實有必定的必要性,會避免一些二義性問題。
(3)using-declarations
這個規則在有多個命名空間的時候很重要。
(4)用int64而不是long
C++下應該統一使用C++的類型
(5)//和註釋之間應該有一個空格
這個應該影響不大
(6)空格代替tab
這個問題在構建之法中也提到過,會影響程序的可讀性,以前沒有注意,以後會改進。
(7)’,‘以後應該空格
以前沒有想到,但彷佛不影響可讀性就能夠。
(8)行結束以前有多餘的空格
這個問題沒有想到,可是其中的意義有什麼意義呢?
(9)代碼塊結束以後有冗餘的空行
同(8),這個規則是爲了讓代碼塊更緊湊嗎?
我和partner商量以後定下了下面的規則:
風格規範:
縮進格式:4個空格
行寬:80個字符
左括號位置:K&R風格
命名風格:小駝峯式命名
長語句的換行:不影響可讀性便可
指針聲明格式:星號緊挨類型
public / protected / private 順序
return以後的表達式是否加圓括號:必要時才加括號
命名空間內代碼是否縮進:不縮進
水平留白:運算符先後留白,函數的參數之間不留白
垂直留白:函數之間留白不超過一行,函數體內留白處加註釋
註釋:每一個函數加註釋
設計規範:
是否支持goto語句:不支持
是否支持struct:不支持
是否支持運算符重載:不支持
變量定義與初始化是否同時完成:是