201871010102-常龍龍 實驗二 個人項目—《求解D{0-1}背包問題》項目報告


項目 內容
課程班級博客鏈接 https://edu.cnblogs.com/campus/xbsf/2018CST?filter=all
這個作業要求鏈接 https://www.cnblogs.com/nwnu-daizh/p/14552393.html
我的課程學習目標 1. 熟悉github操作

2. 熟悉springboot+vue網站開發的技術

3.加深對D{0-1}問題的動態規划和回溯算法的解法的理解

4.熟悉java語言開發程序的一般流程

5.掌握程序設計的模塊化開發

6.掌握PSP流程
這個作業在哪些方面幫助我實現學習目標 1. 更加熟練git的相關操作

2. 熟練markdown編輯器的使用方法

3.溫習使用前后端分離技術開發網站的過程

4.學會算法設計的思想

5.理解了PSP流程對一個項目的重要意義
項目Github的倉庫鏈接地址 1.后台數據接口: https://github.com/beike666/bag_serve

2.前台頁面:https://github.com/beike666/bag_client

博客正文

任務一:閱讀教師博客“常用源代碼管理工具與開發工具”內容要求,點評班級博客中已提交相關至少3份作業。

作業點評鏈接

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

作用

PSP可以幫助軟件工程師在個人的基礎上運用過程的原則,借助於PSP提供的一些度量和分析工具,了解自己的技能水平,控制和管理自己的工作方式,使自己日常工 作的評估、計划和預測更加准確、更加有效,進而改進個人的工作表現,提高個人的工作質量和產量,積極而有效地參與高級管理人員和過程人員推動的組織范圍的 軟件工程過程改進。

我的理解:

每個軟件項目都有自己的特點,因此它們的PSP流程在細節處理上也會各有千秋,但是我們要掌握它的一般流程,知道如何書寫一份正確的PSP流程。

任務三:個人軟件項目開發

一、需求分析

在看到本次個人項目題目中出現散點圖的時候,我就想到要使用javaWeb的方式來完成本次項目,因為我可以將echarts圖表引入到web項目中來實現題目要求,並且使用網頁能讓本次個人項目擁有更加友好的人機交互界面。以下是我基於springboot+vue的網站技術做出的的需求分析:

  1. 后台要能夠從給定的文件中讀取出正確的數據並保存,方便后續的工作

  2. java后端給前端傳遞正確的數據,前端根據后端傳的數據繪制散點圖

  3. java后端實現對自定義數據類型的列表的排序(實現Comparator接口),並向前端傳數據

  4. 實現java后台解決D{0-1}背包問題的動態規划和回溯算法

  5. 后台將求解后的數據寫入文件並保存,前端展示文件下載閱覽

開發環境

名稱 版本
jdk 1.8.0
vue-cli 3.12.1
node.js 14.15.0
git 2.29.1.windows.1

二、功能設計

  • 繪制任意一組D{0-1}KP數據以重量為橫軸、價值為縱軸的數據散點圖

  • 對任意一組D{0-1}KP數據按項集第三項的價值:重量比進行非遞增排序;

  • 用戶能夠自主選擇動態規划算法、回溯算法求解指定D{0-1} KP數據的最優解和求解時間(以秒為單位)

  • 任意一組D{0-1} KP數據的最優解、求解時間和解向量可保存為txt文件或導出EXCEL文件

三、設計實現

1. 主要類

  • FileControler類:負責所有的數據處理並向前端傳遞數據

  • Scatter類:前端通過表單請求數據的有個封裝類,效果是
{
    fileName:"idkp1-10.txt",
    group:1,
//  0代表動態規划算,1代表回溯算法
    type:0,
    fileType:'.txt'
}
  • ScatterUtil類:畫數據散點圖和排序時的一個工具類,效果是
{
    profit:168,
    weight:309
}
  • OrderUtil類:做自定義數據類型排序時的類工具類,效果是
{
 data:[
   {profit:168,weight:309},
   {profit:168,weight:309},
   {profit:168,weight:309}
 ],
 rate:1.0978
}
  • AnswerUtil類:將求解結果返回前端的呢的一個工具類,效果是
{
//  最優解的路徑
    answer:10453,
//  運行時間
    runtime:0.0341,
//  解向量
    bestPath:[]
}

2. 類的關系

3. FileController類中的函數

  • getScatterData:繪制散點圖的后台數據接口

    參數

    • Scatter scatter:其中包含需要繪制散點圖的文件,文件的第幾組數據,采用什么算法(此處為空),保存為什么文件(此處為空

    返回數據類型

[
  {profit:121,weight:456},
  {profit:121,weight:456},
  {profit:121,weight:456},
  {profit:121,weight:456}
]
  • getScatterData:數據非遞增排序的后台數據接口

    參數

    • Scatter scatter:其中包含需要繪制散點圖的文件,文件的第幾組數據,采用什么算法(此處為空),保存為什么文件(此處為空

    返回數據類型

[
  {
    item:[{121,456},{121,456},{121,456}],
    rate:1.234245
  },
  {
    item:[{121,456},{121,456},{121,456}],
    rate:1.234245
  },
  {
    rate:[{121,456},{121,456},{121,456}],
    item:1.234245
  }
]
  • answer:使用動態規划或回溯求解的后台數據接口

    參數

    • Scatter scatter:其中包含需要繪制散點圖的文件,文件的第幾組數據,采用什么算法,保存為什么文件(此處為空

    返回數據類型

{
  answer:10453,
  runTime:0.00363s,
  bestpath:""
}
  • answerAndSave:使用動態規划或回溯求解並保存的后台數據接口

    參數

    • Scatter scatter:其中包含需要繪制散點圖的文件,文件的第幾組數據,采用什么算法,保存為什么文件

    返回數據類型

{
  answer:10453,
  runTime:0.00363s,
  bestPath:"",
  downUrl:'http:localhost:8088/file/2022-3-26-123512354123.txt'
}
  • dp:動態規划算法

    參數

    • ArrayList profitsList:某組數據的價值列表

    • ArrayList weightsList:某組數據的重量列表

    • int volume:某組數據的背包最大容量
  • back:為回溯算法准備數據

    參數

    • ArrayList profitsList:某組數據的價值列表

    • ArrayList weightsList:某組數據的重量列表

    • int volume:某組數據的背包最大容量
  • recursion:回溯算法

    參數

    • ArrayList ret:存放所有結果的列表

    • int volume:某組數據的背包最大容量

    • int[][] p:存放某組價值的二維數組

    • int[][] w:存放某組重量的二維數組

    • int totalProfit:存放回溯過程中的物品總價值

    • int totalProfit:存放回溯過程中的物品總重量

    • int i:回溯過程中訪問的物品二維數組的行下標

    • int j:回溯過程中訪問的物品二維數組的列下標
  • splitDataTwoGroup:將數據分割成【重量,價值】的數組

    參數

    • Scatter scatter:其中包含需要繪制散點圖的文件,文件的第幾組數據,采用什么算法(此處為空),保存為什么文件(此處為空

    • ArrayList scatterUtils:封裝散點數據結果的工具類

  • readFile:創建文件對象,清洗數據的前期准備

    參數

    • String fileName:需要清洗數據的文件

    • Integer group:需要清洗數據的文件中的那一組

    • ArrayList profitsList:將清洗過的組數據的價值保存起來的列表

    • ArrayList profitsList:將清洗過的組數據的重量保存起來的列表

  • splitData:分割具體某一組數據

    參數

    • Integer group:需要分割數據的文件中的那一組

    • ArrayList divided:分割好的數據列表

    • ArrayList undivided:分割好的數據列表
  • clearData:具體的清洗數據的操作

    參數

    • BufferedReader reader:文件讀取流對象

    • ArrayList profits:文件中所有的價值列表(每一組為一個字符串)

    • ArrayList weights:文件中所有的重量列表(每一組為一個字符串)
  • volumeCount:找出文件中某一組組的最大背包容量

    參數

    • String fileName:文件名

    • Integer group:要找出哪一組的最大容量
  • writeTxt:將內容保存為txt文件

    參數

    • File file:文件對象

    • String data:要寫入的數據
  • writeExcel:將內容保存為excel文件

    參數

    • File file:文件對象

    • AnswerUtil answerUtil:要寫入的數據

4. FileController類中函數的關系

5. FileController類中answerAndSave方法流程圖(關鍵方法,也是一個數據接口)

四、測試運行

  1. 繪制任意一組D{0-1}KP數據以重量為橫軸、價值為縱軸的數據散點圖

  1. 對一組D{0-1}KP數據按項集第三項的價值:重量比進行非遞增排序

3.用戶能夠自主選擇動態規划算法、回溯算法求解指定D{0-1} KP數據的最優解和求解時間(以秒為單位)

  • 動態規划算法

  • 回溯算法

  1. 任意一組D{0-1} KP數據的最優解、求解時間和解向量可保存為txt文件或導出EXCEL文件
  • 保存為txt文件

  • 保存為excel文件

五、重要代碼

/* 
  回溯算法
*/
public void recursion(ArrayList<Integer> ret,int volume,int[][] p,int[][] w,int totalProfit,int totalWeight,int i,int j){
  if(j!=3){
//            相當於不選當前的項集
    totalProfit=totalProfit+p[i][j];
    totalWeight=totalWeight+w[i][j];
  }
//        如果加上當前物品時總重量超過了背包容量則返回上一級
  if(totalWeight>volume){
    return;
  } 
//        如果已經遍歷到最后一個元素,則將當前的最大價值存入列表
  if(i==p.length-1){
    ret.add(totalProfit);
    return;
  }
//        便利當前結點的所有子結點
  for (int k = 0; k <4 ; k++) {
    recursion(ret,volume,p,w,totalProfit,totalWeight,i+1,k);
  }
}
/**
 * 將文件中的特定數據讀取到列表中
* @param reader
* @param profits
* @param weights
* @throws IOException
*/
private static void clearData(BufferedReader reader, ArrayList<String> profits, ArrayList<String> weights) throws IOException {
  String s=null;
//            讀取數據的標志字符串
  String profit="The profit of items are:";
  String weight="The weight of items are:";
//            讀取數據的標志位
  int flag1=0;
  int flag2=0;
  ArrayList<Integer> volumes = new ArrayList<>();
  while ((s = reader.readLine()) != null) {
//        如果如果包含profit,則下一行是當前組的所有,設標志為為1,方便下次讀入
    if (s.contains(profit)) {
      flag1=1;
      continue;
    }else if (s.contains(weight)) {
//        如果如果包含weight,則下一行是當前組的所有,設標志為為1,方便下次讀入
      flag2=1;
      continue;
     }
//        如果如果標志位為1,則本行為數據行,讀入后設標志位為0,停止本次讀入
    if(flag1==1){
//        將當前數據存入列表
      profits.add(s);
      flag1=0;
    }else if(flag2==1){
      weights.add(s);
      flag2=0;
    }
  }
}

六、項目總結

我的程序是如何實現軟件設計的“模塊化”原則的?

1. FileController類是我的數據接口層,前台頁面想要請求數據都必須訪問此類中的方法,其中共有四個接口供使用,每個數據接口職能明確,作用分離。

2. 在FileController類中其余的方法都是為上面四個數據接口服務的,當需要什么類型,什么格式的數據時只需傳入相應的參數即可返回正確的結果。例如項目中的每個功能都需要讀入正確格式的數據,這就產生了一個公共的方法readFile來讀文件,而不需要每次都書寫雷同的代碼,大大減少了工作量。

我的感想

1. 此次的個人項目在總體難度上屬於一般難度,最重要的就是要將D{0-1}背包問題的動態規划和回溯算法編寫出來,因為之前沒有學過算法分析這門課,所以這方面知識的不足在整個項目開展過程中帶給我很大的困擾。最后在和舍友請教交流以及自我思考的情況下,終於將本次個人項目功能基本實現。但是依舊沒有寫出使用動態規划和回溯求背包問題的最優解路徑(解向量)的算法,只做出了最優解和求解時間,所以在這點上項目還是有所欠缺。因此今后我需要補習算法方面的知識,加強軟件課程的學習,在遇到任何問題時都能有一個正確的思路,從而“正確求解”。

2. 通過本次個人項目的完成訓練,我更加熟練地掌握了javaWeb網站技術的開發,越來越明白了后端處理數據,前端接收並展示數據的開發思想;對向GitHub倉庫提交項目的一般流程有了更深層次的掌握(因為在push項目時,我經常會遇到各種各樣的錯誤,通過百度查資料,讓我對這些錯誤都有了更深刻的印象,對於解決這些問題也更加得心應手);

3. 本次個人項目更讓我明白了PSP的重要性,通過PSP,我們可以更好地掌握整個項目的開發時間及流程,項目在什么時候進行到什么地步,周期慢了需要加快,項目什么時候能夠完工等等問題。有了一份完整且適當的PSP,對於團隊合作的軟件項目將會有非常大好處。相信在今后的學習生活中,PSP的知識一定會給我帶來更多的幫助。

七、展示PSP

PSP 任務內容 計划共完成需要的時間(h) 實際完成需要的時間(h)
Planning 計划 42.3 46
·Estimate 估計這個任務需要多少時間,並規划大致工作步驟 42.3 46
Development 開發 36.3 39.5
·Analysis 需求分析 (包括學習新技術) 6 7
·Design Spec 生成設計文檔和思路 2 2.4
·Design Review 設計復審 1 0.8
·Coding Standard 代碼規范 (為目前的開發制定合適的規范) 0.3 0.3
·Design 具體設計 5 6
·Coding 具體編碼 18 20
·Code Review 代碼復審 1 1
·Test 測試(自我測試,修改代碼,提交修改) 3 3
Reporting 博客 6 6.5
Summer 任務+總結 6 6.5
任務四:個人軟件項目推送GitHub

一、bag_serve倉庫(后台數據接口)

  • 推送項目展示

  • 提交及推送記錄

二、bag_client倉庫(前台頁面)

  • 推送項目展示

  • 提交及推送記錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM