項目 | 內容 |
---|---|
課程班級博客鏈接 | 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份作業。
作業點評鏈接
- https://www.cnblogs.com/weinana/p/14550875.html
- https://www.cnblogs.com/mayan0821/p/14547899.html
- https://www.cnblogs.com/chms/p/14550446.html
任務二:詳細閱讀《構建之法》第1章、第2章,掌握PSP流程
作用
PSP可以幫助軟件工程師在個人的基礎上運用過程的原則,借助於PSP提供的一些度量和分析工具,了解自己的技能水平,控制和管理自己的工作方式,使自己日常工 作的評估、計划和預測更加准確、更加有效,進而改進個人的工作表現,提高個人的工作質量和產量,積極而有效地參與高級管理人員和過程人員推動的組織范圍的 軟件工程過程改進。
我的理解:
每個軟件項目都有自己的特點,因此它們的PSP流程在細節處理上也會各有千秋,但是我們要掌握它的一般流程,知道如何書寫一份正確的PSP流程。
任務三:個人軟件項目開發
一、需求分析
在看到本次個人項目題目中出現散點圖的時候,我就想到要使用javaWeb的方式來完成本次項目,因為我可以將echarts圖表引入到web項目中來實現題目要求,並且使用網頁能讓本次個人項目擁有更加友好的人機交互界面。以下是我基於springboot+vue的網站技術做出的的需求分析:
- 后台要能夠從給定的文件中讀取出正確的數據並保存,方便后續的工作
- java后端給前端傳遞正確的數據,前端根據后端傳的數據繪制散點圖
- java后端實現對自定義數據類型的列表的排序(實現Comparator接口),並向前端傳數據
- 實現java后台解決D{0-1}背包問題的動態規划和回溯算法
- 后台將求解后的數據寫入文件並保存,前端展示文件下載閱覽
開發環境
名稱 | 版本 |
---|---|
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:某組數據的背包最大容量
- ArrayList
- back:為回溯算法准備數據
參數
- ArrayList
profitsList:某組數據的價值列表
- ArrayList
weightsList:某組數據的重量列表
- int volume:某組數據的背包最大容量
- ArrayList
- recursion:回溯算法
參數
- ArrayList
ret:存放所有結果的列表
- int volume:某組數據的背包最大容量
- int[][] p:存放某組價值的二維數組
- int[][] w:存放某組重量的二維數組
- int totalProfit:存放回溯過程中的物品總價值
- int totalProfit:存放回溯過程中的物品總重量
- int i:回溯過程中訪問的物品二維數組的行下標
- int j:回溯過程中訪問的物品二維數組的列下標
- ArrayList
- splitDataTwoGroup:將數據分割成【重量,價值】的數組
參數
- Scatter scatter:其中包含需要繪制散點圖的文件,文件的第幾組數據,采用什么算法(此處為空),保存為什么文件(此處為空)
- ArrayList
scatterUtils:封裝散點數據結果的工具類
- Scatter scatter:其中包含需要繪制散點圖的文件,文件的第幾組數據,采用什么算法(此處為空),保存為什么文件(此處為空)
- readFile:創建文件對象,清洗數據的前期准備
參數
- String fileName:需要清洗數據的文件
- Integer group:需要清洗數據的文件中的那一組
- ArrayList
profitsList:將清洗過的組數據的價值保存起來的列表
- ArrayList
profitsList:將清洗過的組數據的重量保存起來的列表
- String fileName:需要清洗數據的文件
- splitData:分割具體某一組數據
參數
- Integer group:需要分割數據的文件中的那一組
- ArrayList
divided:分割好的數據列表
- ArrayList
undivided:分割好的數據列表
- Integer group:需要分割數據的文件中的那一組
- clearData:具體的清洗數據的操作
參數
- BufferedReader reader:文件讀取流對象
- ArrayList
profits:文件中所有的價值列表(每一組為一個字符串)
- ArrayList
weights:文件中所有的重量列表(每一組為一個字符串)
- BufferedReader reader:文件讀取流對象
- volumeCount:找出文件中某一組組的最大背包容量
參數
- String fileName:文件名
- Integer group:要找出哪一組的最大容量
- String fileName:文件名
- writeTxt:將內容保存為txt文件
參數
- File file:文件對象
- String data:要寫入的數據
- File file:文件對象
- writeExcel:將內容保存為excel文件
參數
- File file:文件對象
- AnswerUtil answerUtil:要寫入的數據
- File file:文件對象
4. FileController類中函數的關系
5. FileController類中answerAndSave方法流程圖(關鍵方法,也是一個數據接口)
四、測試運行
- 繪制任意一組D{0-1}KP數據以重量為橫軸、價值為縱軸的數據散點圖
- 對一組D{0-1}KP數據按項集第三項的價值:重量比進行非遞增排序
3.用戶能夠自主選擇動態規划算法、回溯算法求解指定D{0-1} KP數據的最優解和求解時間(以秒為單位)
- 動態規划算法
- 回溯算法
- 任意一組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 |
一、bag_serve倉庫(后台數據接口)
- 推送項目展示
- 提交及推送記錄
二、bag_client倉庫(前台頁面)
- 推送項目展示
- 提交及推送記錄