201871010111-劉佳華 實驗三 結對項目—《D{0-1}KP 實例數據集算法實驗平台》項目報告


實驗三 軟件工程結對項目

時間:2021-4-1

項目 內容
課程班級博客鏈接 課程鏈接
這個作業要求鏈接 作業要求
我的課程學習目標 1.了解軟件工程過程中結對項目的開發流程
2. 理解結對編程的重要性
3.提高個人編碼能力
這個作業在哪些方面幫助我實現學習目標 1.通過本次作業的具體流程,使得我了解到了軟件工程中結對任務的開發流程
2.填寫PSP表格
3.個人進行學習相關算法及編碼
4.了解到結對編程中代碼規范,代碼復審的重要性
結對編程隊友學號與姓名 201871010102-常龍龍
結對編程隊友博文地址 201871010102-常龍龍 實驗三 結對項目一《D{0-1}KP 實例數據集算法實驗平台》項目報告
項目Github的倉庫鏈接地址 前台頁面
后端數據接口

1實驗目的與要求

(1) 體驗軟件項目開發中的兩人合作,練習結對編程(Pair programming)。

(2) 掌握Github協作開發程序的操作方法。

2實驗內容和步驟

任務1:閱讀《現代軟件工程—構建之法》第3-4章內容,理解並掌握代碼風格規范、代碼設計規范、代碼復審、結對編程概念;

任務2:兩兩自由結對,對結對方《實驗二 軟件工程個人項目》的項目成果進行評價,具體要求如下:

(1)對項目博文作業進行閱讀並進行評論,評論要點包括:博文結構、博文內容、博文結構與PSP中“任務內容”列的關系、PSP中“計划共完成需要的時間”與“實際完成需要的時間”兩列數據的差異化分析與原因探究,將以上評論內容發布到博客評論區。

(2)克隆結對方項目源碼到本地機器,閱讀並測試運行代碼,參照《現代軟件工程—構建之法》4.4.3節核查表復審同伴項目代碼並記錄。

(3)依據復審結果嘗試利用github的Fork、Clone、Push、Pull request、Merge pull request等操作對同伴個人項目倉庫的源碼進行合作修改。

博客作業中針對任務2的評分要點:

  1. 結對方博客鏈接(1分);
  2. 結對方Github項目倉庫鏈接(1分);
  3. 符合(1)要求的博客評論(18分);
  4. 符合(2)要求的代碼核查表(15分);
  5. 結對方項目倉庫中的Fork、Clone、Push、Pull request、Merge pull request日志數據(5分)

任務3:采用兩人結對編程方式,設計開發一款D{0-1}KP 實例數據集算法實驗平台,使之具有以下功能:

(1)平台基礎功能:實驗二 任務3;

(2)D{0-1}KP 實例數據集需存儲在數據庫;

(3)平台可動態嵌入任何一個有效的D{0-1}KP 實例求解算法,並保存算法實驗日志數據;

(4)人機交互界面要求為GUI界面(WEB頁面、APP頁面都可);

(5)查閱資料,設計遺傳算法求解D{0-1}KP,並利用此算法測試要求(3);

(6)附加功能:除(1)-(5)外的任意有效平台功能實現。

結對編程項目實施要求及代碼部分評分細則(30分):

  1. 結對編程開發進度計划的要求:在項目正式之前,預估本次結對項目任務的PSP環節的消耗時間,並在PSP過程中統計實際耗時,填寫PSP表格。
  2. 嘗試采用漢堡包法實施項目結對中兩個人的溝通,關於漢堡包法的闡述參見:http://www.cnblogs.com/xinz/archive/2011/08/22/2148776.html
  3. 理解領航員和駕駛員兩種角色關系:兩人都必須參與編碼工作,在結對編程中兩個人輪流做對方的角色。
  4. 將結對編程項目的源碼以增量方式提交到指定同學Github賬號的項目倉庫中,Github結對項目倉庫的代碼提交日志要體現兩人合作過程,項目倉庫中要能看到項目多次commit的記錄,和兩人各自的commit記錄。(5分)
  5. 項目必須包含src文件夾;
  6. 編撰兩人合作開發遵守共同認可的編碼規范,提交項目代碼規范文檔到Github項目倉庫根目錄下。(5分)
  7. 程序功能評測。( 20分)

任務4:完成結對項目報告博文作業(30分,以下給出評分細目)

3實驗完成情況

任務1:閱讀《現代軟件工程—構建之法》第3-4章內容,理解並掌握代碼風格規范、代碼設計規范、代碼復審、結對編程概念已完成

代碼規范: 變量名等的規范,縮進格式的規范,函數接口的規范。 原則:代碼簡單易懂,邏輯清晰 面向變化編程,而不是面向需求編程 。代碼風格規范的原則是簡明、易讀、無二異性。

代碼復審: 代碼審查,是有意識地、有系統地與其他程序員一起檢查彼此的代碼是否有錯誤的行為。可以節省一些不必要的時間和資源,提高開發效率。

結對編程: 兩人合作工作與兩個人各自獨立工作相比,結對編程能編寫出質量更高的代碼。在面對一個問題的時候,經過討論會得出一些更好的雙方都支持的解決方案,使問題能夠達到最優程度的解決。

任務2:結對編程已完成

  • 2.1 結對編程名單(常龍龍博客園鏈接

  • 2.2 常龍龍的github倉庫鏈接

  • 2.3 符合相關要求的評論

  • 2.4 代碼核查表

  • 項目的開發者:常龍龍

  • 項目的復審者:劉佳華

    1、概要部分 代碼符合需求和規格說明么? 代碼符合需求
    代碼設計是否考慮周全? 考慮周全
    代碼可讀性如何? 代碼可讀性較強,有着比較好的可讀性。
    代碼容易維護么? 容易維護
    代碼的每一行都執行並檢查過了嗎? 是的,都可以執行
    2.設計規范部分 設計是否遵從已知的設計模式或項目中常用的模式? 遵從
    有沒有硬編碼或字符串/數字等存在? 沒有
    代碼有沒有依賴於某一平台,是否會影響將來的移植(如Win32到Win64)? 沒有,不會影響移植,任何平台都可以
    開發者新寫的代碼能否用已有的Library/SDK/Framework中的功能實現?在本項目中是否存在類似的功能可以調用而不用全部重新實現? 可以用、存在,有些代碼是可以調用的
    有沒有無用的代碼可以清除?(很多人想保留盡可能多的代碼,因為以后可能會用上,這樣導致程序文件中有很多注釋掉的代碼,這些代碼都可以刪除,因為源代碼控制已經保存了原來的老代碼) 基本清除完畢了
    3.代碼規范部分 修改的部分符合代碼標准和風格么? 符合,全都按照代碼標准修改的
    4.具體代碼部分 有沒有對錯誤進行處理?對於調用的外部函數,是否檢查了返回值或處理了異常? 對錯誤都進行了處理,沒有異常
    參數傳遞有無錯誤,字符串的長度是字節的長度還是字符(可能是單/雙字節)的長度,是以0開始計數還是以1開始計數? 無錯誤、本項目中不涉及字符串
    邊界條件是如何處理的?switch語句的default分支是如何處理的?循環有沒有可能出現死循環? switch語句的default分支返回false,沒有出現死循環
    有沒有使用斷言(Assert)來保證我們認為不變的條件真的得到滿足?
    對資源的利用是在哪里申請,在哪里釋放的?有沒有可能導致資源泄露(內存、文件、各種GUI資源、數據庫訪問的連接,等等)?有沒有優化的空間? 在對數據庫進行操作之前申請數據庫連接資源,操作完畢之后釋放申請的資源、不會導致資源泄露、可以優化使用斷言來保證我們認為不變的條件
    數據結構中有沒有用不到的元素? 沒有
    5.效能 代碼的效能(Performance)如何?最壞的情況如何? 達到了具體任務的要求
    代碼中,特別是循環中是否有明顯可優化的部分(C++中反復創建類,C#中 string 的操作是否能用StringBuilder 來優化)? 沒有,已經比較優化了
    對於系統和網絡調用是否會超時?如何處理? 目前沒有出現超時的現象。假如出現了我們會殺毒;整理系統,減少運行的進程,釋放內存、cpu,釋放c盤空間;
    6.可讀性 代碼可讀性如何?有沒有足夠的注釋? 可以順利讀取、代碼有足夠的注釋讓我們讀懂
    7.可測試性 代碼是否需要更新或創建新的單元測試? 有創新點,呈現良好,值得體會
  • 2.5 clone 后運行

    1618277382535

1618201294948
1618201332243

任務3:程序設計以完成

  • 需求分析:

    1. 后台要能夠從給定的文件中讀取出正確的數據並保存到數據庫

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

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

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

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

    6. 后台接收用戶發送的算法文件並運行,將運行結果保存到文件然后返回前端

    7. 后台編寫遺傳算法求解D{0-1}KP
  • 功能設計

    • D{0-1}KP數據可以保存到數據庫,也可以從數據庫中清除

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

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

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

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

    • 平台可動態嵌入任何一個有效的D{0-1}KP 實例求解算法,並保存算法實驗日志數據

    • 平台可使用遺傳算法求解D{0-1}KP
  • 設計實現

  • 1.類之間的關系

  • 2.數據庫表的設計

file_data表

volume表

  • 測試運行
  • 結對編程

    • 任務分功

      • 1、項目剛開始我們在討論是使用哪種人機交互界面,考慮到了使用Java GUI,安卓app等方案,但是基於實驗二的實驗基礎最終出於頁面效果和開發時間進度方面我們選擇javaWeb頁面,並且使用Springboot+vue的開發方式(因為在上次項目常龍龍同學就使用的網站開發,這次只需要在上次的基礎上進行功能擴展);
      • 2、在項目的具體開展過程中,我們各司其職,常龍龍同學負責網站頁面開發,將前后端分離,負責算法設計,網站開發完畢后,我將項目克隆下來,將算法嵌入到后台代碼中,再push上去等等。最終在我們兩個人的合作之下,完成了本次項目開發
    • 結對編程照片


    • github提交圖片





  • 項目總結

    • 1、結對編程有利有弊,但是總的來說是利大於弊的,1+1的效果>2。

    • 2、結對編程也是一次互相學習的過程,在結對的過程中,我們可以互相幫助,分享學習資源,出現問題也可以一起討論解決,大大加快了項目的開展進度。而且我們分工明確,隊友(常龍龍)負責編寫網站,我負責編寫算法,我們各司其職,互相交流,一起合作,最終很好的完成了本次項目。

    • 3、在項目開展過程中,遇到很多的問題,例如網絡質量不佳,GitHub官網進不去,克隆項目也會出現網絡超時的情況,在提交項目的時候也會出現github連接超時的情況,這個比較影響開發效率,還有遺傳算法求解D{0-1}KP,我經過查閱資料,最終只做出了遺傳算法求解0-1問題,而對於使用遺傳算法實現折扣背包問題而言,沒有實現。所以最終根據自己的情況,將實驗要求中和了一下,只實現了0-1背包問題的求解,所以項目在這方面還有所欠缺。

    • 4、在結對過程我也看到了自己能力上的缺陷,以前學習的時候重視理論課而疏於實踐課,導致和別人在動手實踐上面的差距,看着隊友(常龍龍)能夠使用當前比較熱門的技術去實現比較精美的網頁時,內心還是比較失落的,但是同時,更多的是鼓舞。以隊友的強大時刻來警醒自己。此外,我還對於一些關於網站設計的思想,我也請教了隊友,總體來說,是一次比較不錯的合作體驗。



附錄:

一、結對編程遵守代碼規范

  1. 開始時間: 2021年4月1日 下午午5時35分
    結束時間: 2021年4月14日 晚上11時22分

  2. 格式
    A. 代碼行數
    (1) 代碼文件不超過500行
    (2) 函數的行數不超過50行
    B. 換行
    (1) 函數與函數之間空一行
    (2) 函數內部變量聲明與函數內部邏輯代碼之間空一行
    (3) 函數內部不同邏輯代碼之間空一行
    C. 大括號
    “{”和“}”必須單獨在一行上,且上下對齊。
    D. 縮進
    代碼縮進一致使用Tab實現,規定Tab鍵寬度為4個字符,不建議使用空格進行縮進。
    E. 空格
    (1) 函數參數列表中不同參數之間應該用一個空格分開,即逗號后面應跟一個空格。如:void updateData(int source, int target)
    (2) for循環中表達式之間應該用一個空格分開,即分號后面應跟一個空格。如:for(exp1; exp2; exp3)
    (3) 操作符與操作數之間應該用一個空格分開,一元操作符(例如自增“++”,自減“--”等)與操作符不作此限定。如:a += b + c; ++a;

  3. 命名
    變量主要分為類的公有和私有變量,方法的參數變量與內部使用的臨時變量。
    A. 變量的名稱由多個名詞單詞或一個名詞單詞組成時,第一個單詞首字母小寫,其他單詞首字母均大寫。如makeRule。
    B. 對於const常量,所有單詞均大寫,且單詞之間由下划線”_”連接,如APP_NAME。
    C. 函數名稱的第一個單詞為小寫的動詞。如isValidExp(表達式是否合法)。
    D. 變量名和函數名能夠表達它所具有的實際含義。如函數名isValid表示返回值是否合法,res表示是返回值。
    E. 盡量避免單詞縮寫,即便它可能是眾所周知的。

  4. 注釋
    A. 采用“//”作為單行注釋符,采用“/**/”作為函數或者方法的注釋。
    B. 注釋的位置
    (1) 注釋在被注釋函數定義的頂部

    ​ (2) 注釋在函數內部變量聲明的右邊

    ​ (3) 注釋在函數內部邏輯代碼的頂部

    C. 注釋的內容
    (1) 代碼的功能

    ​ (2) 對讀者閱讀代碼時可能產生的疑問做解釋,比如,該段代碼使用了堆棧,為什么需要堆棧而並非數組,在此處代碼部分給出注釋


二、結對編程psp時間安排表

PSP 任務內容 計划共完成需要的時間(h) 實際完成需要的時間(h)
·Estimate 估計這個任務需要多少時間,並規划大致工作步驟 0.5 1
Development 開發 36.8 38.4
·Analysis 需求分析 (包括學習新技術) 1 1
·Design Spec 生成設計文檔和思路 1 2
·Design Review 設計復審 0.5 0.6
·Coding Standard 代碼規范 (為目前的開發制定合適的規范) 0.3 0.3
·Design 具體設計 1 1
·Coding 具體編碼 30 30
·Code Review 代碼復審 2 2
·Test 測試(自我測試,修改代碼,提交修改) 1 1.5
Reporting 博客 4 8

三、遺傳算法

import java.io.*;

import java.util.*;

class MaxValue {
    public static int[] have = null;
    public static int max_value = 0;
}

class Global {
    public final static int M = 200;
    public final static int T = 1000;
    public final static double pc = 0.8;
    public final static double pv = 0.05;
}

public class GasolvePackage {
    private int package_rj = 0;
    private int num = 0;
    private int[] tiji = null;
    private int[] value = null;
    private int[][] zq = null;

    public GasolvePackage(String profitString, String valueString, String valume) {
        // try {
        //  BufferedReader read = new BufferedReader(new InputStreamReader(new FileInputStream("./data/input.txt")));
        String a = profitString;
        String b = valueString;
        package_rj = Integer.parseInt(valume);
        //a = read.readLine();
        tiji = strArr_to_intArr(a.split(","));
        // b = read.readLine();
        value = strArr_to_intArr(b.split(","));
        num = value.length;
        MaxValue.have = new int[Global.M];
    }


    private int[] strArr_to_intArr(String[] strArr) {
        int size = strArr.length;
        int[] int_arr = new int[size];
        for (int i = 0; i < size; i++) {
            int_arr[i] = Integer.valueOf(strArr[i].trim());
        }
        return int_arr;
    }

    private int[][] dCopy(int[][] source) {
        int row_num = source.length;
        int col_num = source[0].length;
        int[][] des = new int[row_num][col_num];
        for (int i = 0; i < row_num; i++) {
            for (int j = 0; j < col_num; j++) {
                des[i][j] = source[i][j];
            }
        }
        return des;
    }

    public int[][] init() {
        Random rand = new Random();
        zq = new int[Global.M][num];
        for (int i = 0; i < Global.M; i++) {
            for (int j = 0; j < num; j++) {
                zq[i][j] = rand.nextInt(2);
            }
            if (get_singleWeight(zq[i]) > package_rj) {
                i--;
            }
        }
        return zq;
    }

    private int get_singleWeight(int[] single) {
        int total_weight = 0;
        int size = single.length;
        for (int i = 0; i < size; i++) {
            total_weight += tiji[i] * single[i];
        }
        return total_weight;

    }


    private int get_singleValue(int[] single) {
        int total_value = 0;
        int size = single.length;
        for (int i = 0; i < size; i++) {
            total_value += value[i] * single[i];
        }
        return total_value;
    }


    public void get_maxValue_single(int[][] popu) {
        int size = popu.length;
        int[] fitness = new int[size];
        for (int i = 0; i < size; i++) {
            fitness[i] = get_singleValue(popu[i]);
        }
        int id = 0;

        int max_value = fitness[0];

        for (int j = 1; j < size; j++) {
            if (fitness[j] > max_value) {
                max_value = fitness[j];
                id = j;
            }
        }
        if (max_value > MaxValue.max_value) {
            MaxValue.max_value = max_value;
            int[] have = new int[num];

            for (int i = 0; i < num; i++) {
                have[i] = popu[id][i];
            }
            MaxValue.have = have;
        }
    }


    public double[] getFitness(int[][] popu) {
        int size = popu.length;

        double[] fitness = new double[size];

        for (int i = 0; i < size; i++) {
            fitness[i] = get_singleValue(popu[i]);

        }
        return fitness;

    }


    private double[] get_selectRate(double[] fitness) {
        double sum = 0;
        int size = fitness.length;
        double[] select_rate = new double[size];
        for (int i = 0; i < size; i++) {
            sum += fitness[i];

        }
        for (int j = 0; j < size; j++) {
            select_rate[j] = fitness[j] / sum;
        }
        return select_rate;
    }


    private double[] get_accuRate(double[] select_rate) {
        int i = 0;
        double[] accu_rate = new double[select_rate.length];
        for (i = 0; i < select_rate.length; i++) {
            accu_rate[i] = select_rate[i];
        }
        for (i = 1; i < select_rate.length; i++) {
            accu_rate[i] += accu_rate[i - 1];
        }
        return accu_rate;
    }

    public int[][] select(double[] select, int[][] zhong) {
        Random rand = new Random();
        double t = 0;
        int[][] ans = new int[Global.M][num];
        for (int i = 0; i < zhong.length; i++)
            for (int j = 0; j < zhong[0].length; j++)
                ans[i][j] = zhong[i][j];
        for (int i = 0; i < Global.M; i++) {
            t = rand.nextInt(101) / 100;
            for (int j = 0; j > num; j++)
                if (t <= select[j]) {
                    for (int p = 0; p < num; p++)
                        ans[i][p] = zhong[j][p];
                    break;
                }
        }
        return ans;
    }


    public int[][] crossover(int[][] select_zq) {
        int i = 0;
        Random rand = new Random();
        int random_pos = 0, temp = 0;
        int cross_num = (int) (Global.pc * Global.M);
        int[][] cross_popu = new int[Global.M][num];
        cross_popu = dCopy(select_zq);
        for (i = 1; i < cross_num; i += 2) {
            random_pos = rand.nextInt(num);
            temp = cross_popu[i][random_pos];
            cross_popu[i][random_pos] = cross_popu[i - 1][random_pos];
            cross_popu[i - 1][random_pos] = temp;
            if (get_singleWeight(cross_popu[i]) > package_rj || get_singleWeight(cross_popu[i - 1]) > package_rj) {
                temp = cross_popu[i][random_pos];
                cross_popu[i][random_pos] = cross_popu[i - 1][random_pos];
                cross_popu[i - 1][random_pos] = temp;
            }
        }
        return cross_popu;
    }


    public int[][] variation(int[][] cross_zq) {
        int i = 0;
        int row_id = 0;
        int col_id = 0;
        Random rand = new Random();
        int variation_num = (int) (Global.pv * Global.M * num);
        int[][] variation_zq = new int[Global.M][num];
        variation_zq = dCopy(cross_zq);
        for (i = 0; i < variation_num; i++) {
            row_id = rand.nextInt(Global.M);
            col_id = rand.nextInt(num);
            variation_zq[row_id][col_id] = 1 - variation_zq[row_id][col_id];
            if (get_singleWeight(variation_zq[row_id]) > package_rj) {
                variation_zq[row_id][col_id] = 1 - variation_zq[row_id][col_id];
            }
        }
        return variation_zq;
    }


    public void allway() {
        int popu_id = 1;
        double[] fitness = null;
        double[] select_rate = null;
        double[] accu_rate = null;
        int[][] select_popu = null;
        int[][] cross_popu = null;
        int[][] popu = init();
        get_maxValue_single(popu);
        while (popu_id < Global.T) {
            fitness = getFitness(popu);
            select_rate = get_selectRate(fitness);
            accu_rate = get_accuRate(select_rate);
            select_popu = select(accu_rate, popu);
            cross_popu = crossover(select_popu);
            popu = variation(cross_popu);
            popu_id++;
            get_maxValue_single(popu);
        }
    }


    public int show() {
        return MaxValue.max_value;
    }

    public static void main(String[] args) {
        String[] m = new String[10];
//        m[0]="408,921,1329,11,998,1009,104,839,943,299,374,673,703,954,1657,425,950,1375,430,541,971,332,483,815,654,706,1360,956,992,1948,";
//        m[1]="508,1021,1321,111,1098,1196,204,939,1107,399,474,719,803,1054,1781,525,1050,1362,530,641,903,432,583,894,754,806,1241,1056,1092,1545,";
//        m[2]="10149";

        GasolvePackage ga = new GasolvePackage(args[0], args[1], args[2]);
        ga.allway();
        int ret = ga.show();
        System.out.println("*******");
        System.out.println(ret);
    }
}


免責聲明!

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



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