1. 程式人生 > 其它 >201971010111-何晨澤 實驗二 個人專案—《{0-1}KP問題》專案報告

201971010111-何晨澤 實驗二 個人專案—《{0-1}KP問題》專案報告

專案 內容
課程班級部落格連結 2019級卓越工程師班
這個作業要求連結 實驗二 軟體工程個人專案
我的課程學習目標 (1)掌握軟體專案個人開發流程
(2)掌握Github釋出軟體專案的操作方法
這個作業在哪些方面幫助我實現學習目標 (1)通過D{0-1}問題這一專案,對軟體專案個人開發流程進行實戰
(2)通過將完成的D{0-1}問題專案上傳至Github,對釋出軟體專案的方法進行掌握
專案Github的倉庫連結地址 201971010111_HCZ_EX2

任務1:閱讀教師部落格“常用原始碼管理工具與開發工具”內容要求,點評班級部落格中已提交相關至少3份作業

評論地址 評論內容
201971010140-魏瑾川 實驗一 軟體工程準備—軟體工程的第一印象 內容精練,排版整齊美觀,對各項要求均有較好的實現。同時在問題中融入自己的思考,予人啟發。
201971010160-謝家俊 實驗一 軟體工程準備—初識軟體工程 排版簡潔,條理清晰,基本完成了要求的內容。提問的三個問題偏向基礎概念,有助於知識點的鞏固。
201971010241-王晨陽 實驗一 軟體工程準備-新人報道 條目清楚,詳略得當,較為全面的闡述了完成任務的過程,且對於所提的問題加以底色進行強調,突出重點。

任務2:總結詳細閱讀《構建之法》第1章、第2章,掌握PSP流程

  1. 第一章: 主要講解了 1.軟體=程式+軟體工程;2.軟體工程的定義

    • 軟體=程式+軟體工程:
      鄒欣老師首先解釋了什麼是“軟體”,什麼是“程式”,為我們介紹了軟體工程的概念。最後講述了軟體開發的不同階段,引出了什麼是軟體工程這個問題。
    • 軟體工程的定義:
      軟體工程的特殊性:複雜性,不可見性,易變性,服從性,非連續性;
      軟體工程的知識領域、軟體工程的三大類基礎知識領域:計算基礎,數學基礎和工程基礎;
      軟體工程的目標:使用者滿意度,可靠性,軟體流程的質量,可維護性。
  2. 第二章: 主要講解了PSP,即Personal Software Process,個人軟體開發流程

    • PSP特點:
      • 不侷限於某一種軟體技術,而是著眼於軟體開發的流程。
      • 不依賴於考試,而是依賴工程師自己收集資料,然後分析,提高。
      • 依賴於資料
    • PSP作用:
      PSP可以幫助軟體工程師在個人的基礎上運用過程的原則,藉助於PSP提供的一些度量和分析工具,瞭解自己的技能水平,控制和管理自己的工作方式,使自己日常工作的評估、計劃和預測更加準確、更加有效,進而改進個人的工作表現,提高個人的工作質量和產量,積極而有效地參與高階管理人員和過程人員推動的組織範圍的軟體工程過程改進。

任務3:專案開發

  1. 專案背景:
    {0-1}揹包問題:有N件物品和一個容量為M的揹包。第i件物品所佔空間是w[i],價值是v[i]。求解將哪些物品裝入揹包可使價值總和最大,對於每件物品,僅有取與不取兩個狀態。

  2. 需求分析:
    通過對需求文件進行分析,得到系統有如下模組:

    • 資料讀入與處理:
      正確讀入實驗資料檔案的有效{0-1}KP資料,並將其處理為便於後續操作的資料形式。
    • 散點圖繪製:
      繪製任意一組{0-1}KP資料以價值重量為橫軸、價值為縱軸的資料散點圖。
    • 排序:
      對任一組{0-1}KP資料按重量比進行非遞增排序。
    • 貪心演算法:
      採用貪心演算法求解不超過揹包容量的最大價值和解向量。
    • 動態規劃演算法:
      採用動態規劃演算法求解不超過揹包容量的最大價值和解向量。
    • 回溯演算法:
      採用回溯演算法求解不超過揹包容量的最大價值和解向量。
    • 檔案儲存:
      將求解時間,最大價值,解向量儲存至txt檔案中。
    • 擴充套件功能:
      實現揹包剩餘價值與最大價值之比的比例圖繪製,以扇形圖的形式呈現。
  3. 功能設計:
    根據需求分析,我繪製瞭如下的功能設計圖。

  4. 設計實現:
    系統執行過程如下。

    • 主類 (\(main\)): 包含除擴充套件功能外其餘功能
      • 資料讀入與處理
        • 一個 \(ReadFile()\) 函式負責處理資料讀入與處理,詳細流程如下。
        • 所給資料集的形式較為有序,格式固定。故僅需按照給定格式讀入並儲存即可。
      • 散點圖繪製
        • 一個 \(PlottingScatterPlots()\) 函式負責散點圖的繪製,同時需要重寫 \(paintComponent()\) 函式。
        • 為確定散點圖的邊界,還需獲取價值和重量的最大值,採用 \(getMaxValue()\)\(getMaxWeight()\) 兩個函式獲取,以 \(MaxW\)\(MaxV\) 儲存。
      • 排序
        • 一個 \(DataSort()\) 函式負責資料的排序,採用了較為基本的氣泡排序方法。同時,為了解決資料交換(Java的資料交換方式與C/C++不同),採用 \(SwapInt()\)\(SwapDouble()\) 兩個函式分別實現 \(int\) 型別資料和 \(double\) 型別資料的交換。
      • 貪心、動態規劃、回溯
        • 貪心演算法用一個 \(Greedy()\) 函式實現,由於在此前已經按照重量比進行了排序,故此處直接使用重量比進行貪心。
        • 動態規劃演算法用一個 \(DP()\) 函式實現,給出動態轉移方程為: \(f[j]=max(f[j], f[j-Weight[i]]+Value[i])\) 。同時,還使用了一個 \(FindPath()\) 函式來獲取其解向量。
        • 回溯演算法使用了一個 \(BackTrack()\) 函式和一個限界函式(以貪心的思路實現) \(Bound()\) 實現,其詳細流程如下。
      • 檔案儲存
        • 一個 \(WriteFile()\) 函式實現將結果寫入txt檔案。
    • Addition類:實現擴充套件功能 (扇形圖繪製)
      • 類似的,重寫 \(paintComponent()\) 函式用以繪製扇形圖。繪製扇形圖時需要從主類中傳入比例資料。
  5. 程式碼規範:

專案 規則
縮排 使用 \(tab\) 作為縮排
變數命名 1. 均不能以下劃線開始,也不能以下劃線結束
2. 禁止英文與拼音混用,僅允許純拼音或純英文
3. 採用類駝峰形式,命名首字母可小寫,如 getMaxWeightWriteFile
4. 允許單個小寫英文字母的命名
5. 允許純大寫英文字母的命名
每行最多字元數 單行字元數限制不超過256個
函式最大行數 單個函式行數限制不超過120行
函式、類命名 1. 均不能以下劃線開始,也不能以下劃線結束
2. 禁止英文與拼音混用,僅允許純拼音或純英文
3. 採用類駝峰形式,命名首字母可小寫,如 getMaxWeightWriteFile
4. 允許純大寫英文字母的命名
常量 同變數命名規則
空行規則 1. 引入標頭檔案其間部分不允許空行
2. 靜態變數/常量定義後跟一空行
3. 每個函式後跟一空行,除非是最後一個函式
4. 若函式為空,中間包含一空行
5. 其餘除為了程式碼美觀的空行,均不允許空行出現
註釋規則 1. 行內註釋可使用//...形式
2. 函式前部註釋需使用/*內容/形式
操作符前後空格 1. if/for/while/switch/do等保留字與左右括號之間都必須加空格
2. 其餘運算子左右均不加空格
其他規則 1. 左大括號前不換行
2. 右大括號前換行
  1. 程式碼展示:
  • 動態規劃
f=new int[10010];
for (int i=1;i<=n;i++) {
    for (int j=m;j>=Weight[i];j--) {
        f[j]=Math.max(f[j],f[j-Weight[i]]+Value[i]); //優化後,僅使用一維
    }
}
Res=f[m];
  • 散點圖繪製
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2D=(Graphics2D)g;
    g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    int Width=getWidth();
    int Height=getHeight();
    g2D.draw(new Line2D.Double(Space,Space,Space,Height-Space)); //繪製x軸
    g2D.draw(new Line2D.Double(Space,Height-Space,Width-Space,Height-Space)); //繪製y軸
    Font font=new Font("Microsoft YaHei UI",Font.PLAIN,10); //修改字型
    g2D.setFont(font);
    g2D.drawString("0",Space-10,Height-Space+10); //新增文字
    g2D.drawString("Weight",Width-Space-20,Height-Space+10);
    g2D.drawString("Value",Space-10,Space-5);
    double xAxis=(double)(Width-2*Space)/getMaxWeight();
    double yAxis=(double)(Height-2*Space)/getMaxValue();
    g2D.setPaint(Color.pink);
    for (int i=1;i<=n;i++) { //開始繪製點
        double x=Space+xAxis*Weight[i];
        double y=Height-Space-yAxis*Value[i];
        g2D.fill(new Ellipse2D.Double(x-2,y-2,4,4));
    }
}
  • 擴充套件功能 (扇形圖繪製)
protected void paintComponent(Graphics g){
    int CenterX,CenterY;
    int r;
    int Percent=(int)(360*((double)ArcAns/TotalValue)); //計算可容納所佔角度
    CenterX = this.getWidth();
    CenterY = this.getHeight();
    r = this.getWidth()-10;
    super.paintComponent(g);
    g.setColor(Color.pink);
    g.fillArc(5, 10, r, r, 0, Percent); //繪製可容納部分
    g.setColor(Color.lightGray);
    g.fillArc(5,10,r,r,Percent,360-Percent); //繪製剩餘部分
    Font font=new Font("Microsoft YaHei UI",Font.PLAIN,10); //修改字型
    g.setFont(font);
    g.setColor(Color.black);
    g.drawString("粉色:揹包可容納價值",5,300);
    g.drawString("灰色:物品剩餘價值",150,300);
}
  1. 測試執行
    為便於展示,以第二組資料為例,分別測試貪心、動態規劃和回溯的結果。

    • 貪心演算法
    • 動態規劃演算法
    • 回溯演算法
    • 檔案儲存
  2. 模組化
    設計該專案時,程式碼規範的核心為可讀性,其實現方法為模組化程式設計。
    具體實現為將不同功能分別寫在不同的方法之中,同時如果在某一段方法內其中一段程式碼重複出現,那麼就將該程式碼再次進行封裝,寫在一個獨立的方法裡面,要使用時就進行呼叫。例如,用於交換資料的 \(SwapInt()\)\(SwapDouble()\) ,即模組化的體現之一。

  3. PSP展示

PSP2.1 任務內容 計劃共完成需要的時間(min) 實際完成需要的時間(min)
Planning 計劃 6 8
- Estimate - 估計這個任務需要多少時間,並規劃大致工作步驟 6 8
Development 開發 510 490
- Analysis - 需求分析(包括學習新技術) 10 6
- Design Spec - 生產設計文件 10 8
- Design Review - 設計複審(和同事稽核設計文件) 5 6
- Coding Standard - 程式碼規範(為目前的開發指定合適的規範) 10 20
- Design - 具體設計 25 30
- Coding - 具體編碼 300 260
- Code Review - 程式碼複審 30 30
- Test - 測試(自我測試,修改程式碼,提交修改) 120 130
Reporting 報告 60 62
- Test Report - 測試報告 30 25
- Size Measurement - 計算工作量 10 13
- Postmortem & Process Improvement Plan - 事後總結,並提出過程改進計劃 20 24
  • PSP總結
    總的來說,計劃時間與實際時間較為接近,時間誤差最大的部分在於具體編碼的部分。開始時認為自己對Java的生疏會致使編碼時間的增加,後來實際編碼過程中並未遇到過大的問題,且在遇到問題時,均通過閱讀文件快速解決,故在具體編碼方面,計劃時間相比實際時間較長。
  1. 個人專案總結
    i.{0-1}KP問題:本次專案涉及問題我在高中時期就有過接觸,故對於問題的求解和規劃便可節省大量時間。本次個人專案也是對此前所學知識的鞏固和總結,對於{0-1}KP這一經典問題也有了更深刻的理解。
    ii.專案開發:本次專案是我第一次以軟體工程的角度開發,此前雖有專案開發經驗,但並未通過PSP等方式規範自己的開發。本次的開發採取了規範流程,對以後的專案開發奠定了基礎。
    iii.不足:本次專案的可擴充套件性較差,還有提高的空間。

任務4:完成任務3的程式開發,將專案原始碼的完整工程檔案提交到你註冊Github賬號的專案倉庫中

按照要求,將完整工程檔案提交至專案倉庫,命名為201971010111_HCZ_EX2,如下圖所示。

  1. commit的使用
    本次專案的開發共使用了17次commit,如下圖所示。

  2. issues的使用
    本次專案的開發共發表兩條issues,主要用於記錄功能及作提示作用,如下圖所示。

  3. release的使用
    本次專案共使用兩次realease功能,即釋出了兩個版本,分別為V1.1和V1.2,如下圖所示。