軟工1816 · 第二次作業 - 個人項目
一、Github地址 課程項目要求
二、PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | ||
· Estimate | · 估計這個任務需要多少時間 | 510 | 570 |
Development | 開發 | ||
· Analysis | · 需求分析 (包括學習新技術) | 60 | 60 |
· Design Spec | · 生成設計文檔 | ||
· Design Review | · 設計復審 | 10 | 10 |
· Coding Standard | · 代碼規範 (為目前的開發制定合適的規範) | 10 | 10 |
· Design | · 具體設計 | 30 | 30 |
· Coding | · 具體編碼 | 300 | 360 |
· Code Review | · 代碼復審 | 20 | 20 |
· Test | · 測試(自我測試,修改代碼,提交修改) | 20 | 20 |
Reporting | 報告 | ||
· Test Repor | · 測試報告 | 20 | 20 |
· Size Measurement | · 計算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事後總結, 並提出過程改進計劃 | 30 | 30 |
合計 | 510 | 570 |
三、解題思路。即剛開始拿到題目後,如何思考,如何找資料的過程。
C++ 怎麽讀寫文件?
學習了如何使用C++文件讀寫,使用頭文件
怎麽識別單詞並統計個數?
可以創建結構體數組用來存每類單詞和對應的個數,遍歷一遍整個文檔,以英文字母為開頭的詞語先暫時存在臨時結構體中,全部讀完該詞語再進行判斷是否符合單詞規範,再跟單詞結構數組對比,相同的單詞數量加一,都不一樣則存新的結構數組中。
怎麽對單詞數量排序,並且相同數量的按字典排序?
使用優先隊列,之前存的單詞數組放入優先隊列中,個數多的優先,個數相同的,按單詞字母字典排序優先。
怎麽統計單詞數,字符數,行數?
定義全局變量,識別到符合單詞規範,單詞數量累加;按要求,遍歷文檔時字符Ascii碼在0-127之間則字符數累加;重新按行遍歷文檔,每遍歷一行,行數累加。
四、設計實現過程。設計包括代碼如何組織,比如會有幾個類,幾個函數,他們之間關系如何,關鍵函數是否需要畫出流程圖?單元測試是怎麽設計的?
定義全局變量計算個數,結構體數組存單詞,一個主函數,調用三個函數:一個countChar(string u)//統計字符數,單詞放入優先隊列中,一個countLines(string u)//返回有效行數,一個輸出函數print(string u)// 按要求輸出到文件result.txt。
簡單的單元測試:
測試一
測試二
五、記錄在改進程序性能上所花費的時間,描述你改進的思路,並展示一張性能分析圖(由VS 2017的性能分析工具自動生成),並展示你程序中消耗最大的函數。
判斷單詞是否是新單詞還是重復單詞時所花費的時間較長,每次都從頭遍歷數組,但是按這個方法來做,所花費的時間是必須的,要改進只能重新換一種方法來做。
可以看到main函數占99.28%,countChar()占2.27%,print()占9.83%。占消耗最大的是優先隊列的排序函數占了主要的86.37%
六、代碼說明。展示出項目關鍵代碼,並解釋思路與註釋說明。
- 統計行數,按行遍歷文檔,每遍歷一行,行數累加
int countLines(string u) //統計行數
{
int lines = 0;
ifstream fin;
fin.open(u);//打開文件
if (!fin)
{
cout << "can not open file" << endl;
}
string s;
while (getline(fin, s))lines++;//行遍歷一遍,計算行數
fin.close();
return lines;
}
- 遍歷文件識別單詞並記錄,創建結構體數組用來存每類單詞和對應的個數,遍歷一遍整個文檔,以英文字母為開頭的詞語先暫時存在臨時結構體中,全部讀完該詞語再進行判斷是否符合單詞規範,再跟單詞結構數組對比,相同的單詞數量加一,都不一樣則存新的結構數組中。
void countChar(string u)//統計字符數、單詞放在全局變量、優先隊列中
{
wo *danci = new wo[9999999];//動態分配結構體數組
wo temp_danci;
int k, i, j, flag,n=0;
char ch;
ifstream fin;
fin.open(u);//打開文件
if (!fin)
{
cout << "can not open file" << endl;
}
while (!fin.eof())
{
ch = fin.get();
if(ch>=0 && ch<=255)
characters++;
//判斷是否為單詞
if ((ch >= ‘a‘&&ch <= ‘z‘) || (ch >= ‘A‘&&ch <= ‘Z‘))
{
k = 0;
flag = 0;
temp_danci.count = 1;
while ((ch >= ‘a‘&&ch <= ‘z‘) || (ch >= ‘A‘&&ch <= ‘Z‘) || (ch >= ‘0‘&&ch <= ‘9‘))
{
if (ch >= ‘A‘&&ch <= ‘Z‘)
ch += 32;
temp_danci.word[k++] = ch;
ch = fin.get();
if (ch >= 0 && ch <= 255)
characters++;
}
temp_danci.word[k++] = ‘\0‘;
for (i = 0; i < 4; i++)
{
if ((temp_danci.word[i] >= ‘0‘&&temp_danci.word[i] <= ‘9‘) || temp_danci.word[i] == ‘\0‘)
{
flag = 1;//判斷是否符合單詞規範
break;
}
}
if (flag == 0)
{
words++;
j = n;
for (i = 0; i<j; i++)//相同的單詞個數累加
{
if (strcmp(temp_danci.word, danci[i].word) == 0)
{
danci[i].count++;
break;
}
}
if (n == 0 || i == j)//新單詞生成新的空間
{
danci[n] = temp_danci;
n++;
}
}
}
else continue;
}
fin.close();
for (int i = 0; i < n; i++)//放入優先隊列
{
tmp.push(danci[i]);
}
}
- 自定義優先隊列排序方式,個數多的單詞優先,個數相同的,按單詞字母字典排序優先。
bool operator< (wo a, wo b)//自定義排序
{
//個數相同的單詞按字典排序
if (a.count == b.count)
{
int i = -1;
do {
i++;
} while (a.word[i] == b.word[i]);
return a.word[i] > b.word[i];
}
//出現頻率排序
else return a.count < b.count;
}
- 輸出到文件result.txt
void print(string u)//輸出到文件
{
int x = 0;
ofstream outf;
outf.open("result.txt");
outf << "characters: " << characters << endl;
outf << "words: " << words << endl;
outf << "lines: " << countLines(u) << endl;
while (!tmp.empty() && x<10)//輸出前十個單詞
{
outf << "<" << tmp.top().word << ">: " << tmp.top().count << endl;
tmp.pop();
x++;
}
outf.close();
}
- 主函數
int main(int argc, char* argv[]) {
string url = argv[1];//文件路徑
countChar(url);
print(url);
return 0;
}
- 代碼覆蓋率
利用插件OpenCppCoverage,查看代碼覆蓋率
- 異常處理
輸入一個不存在的文件,返回打開文件失敗
七、解決項目的心路歷程與收獲。
剛開始看到題目要求時,心情十分復雜,很多專業名詞都看不懂,要求不知道怎麽實現,邊查邊讀懂題目要求後,才明白了自己哪裏不會,需要學什麽,首先學了怎麽C++讀寫一個txt文件,然後將讀取的內容轉換成之前c語言做過的字符串處理的題目,來編寫代碼實現相應的功能,再將函數封裝優化。也學習了GitHub的使用,了解了《構建之法》中講的一個項目從需求分析到開發的具體流程,所花時間的PSP記錄,單元測試,異常處理等步驟。由於做的比較倉促,項目中還有很多不足,如接口封裝沒有做好,要學習的還有很多,好好努力吧!
軟工1816 · 第二次作業 - 個人項目