1. 程式人生 > >軟工1816 · 第二次作業 - 個人項目

軟工1816 · 第二次作業 - 個人項目

數組 說明 bool image work 提交 估計 專業 while

一、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 · 第二次作業 - 個人項目