201971010237-尚洁 实验二 个人项目—《背包问题》项目报告

项目 内容
课程班级博客链接 2019级卓越工程师班
作业要求连接 实验二 软件工程个人项目
我的课程学习目标 (1)掌握软件项目个人开发流程。
(2)掌握Github发布软件项目的操作方法。
这个作业在哪些方面帮助我实现学习目标 1)作业中的步骤指导使我可以快速地了解如何使用博客
2)了解了Github的基本操作
3)通过实践动手学习知识
项目Github的仓库链接地址 https://github.com/sj319134578/SJ

正文:

任务1:阅读教师博客“常用源代码管理工具与开发工具”内容要求,点评班级博客中已提交相关至少3份作业

201971010231-毛玉贤 实验一 软件工程准备—基本操作及《构建之法》初步三问 https://www.cnblogs.com/Moki231/p/15954473.html
201975060130-张蓉星 实验一 软件工程准备—初识软件工程 https://www.cnblogs.com/zrx04/p/15954327.html
201971010216-李斌 实验一 软件工程准备一 阅读《构建之法现代软件工程》有感 https://www.cnblogs.com/1810067010LB/p/15969385.html

任务2:总结详细阅读《构建之法》第1章、第2章,掌握PSP流程

1.第一章

  • 软件=程序+软件工程:
    软件工程的特殊性:复杂性,不可见性,易变性,服从性,非连续性;
    软件工程的知识领域、软件工程的三大类基础知识领域:计算基础,数学基础和工程基础;
    软件工程的目标:用户满意度,可靠性,软件流程的质量,可维护性。

2. 第二章

  • 软件的很多错误都来源于程序员对模块功能的误解、疏忽或不了解模块的变化。为了能让自己负责的模块功能定义尽量明确,模块内部的改变不会影响其他模块,而且模块的质量能得到稳定的、量化的保证,单元测试必不可少。
  • 好的单元测试的标准有:
    1)单元测试应该在最基本的功能或参数上验证程序的正确性
    2)单元测试必须由最熟悉代码的人来写
    3)单元测试后,机器状态保持不变
    4)单元测试要快,保持效率
    5)单元测试应该产生可重复、一致的结果
    6)单元测试具有独立性
    7)单元测试应该覆盖所有代码路径
    8)单元测试应该集成到自动测试的框架中
    9)单元测试必须和产品代码一起保护和维护
  • PSP特点:
    不局限于某一种软件技术(如编程语言),而是着眼于软件开发的流程,这样,开发
    不同应用的软件工程师可以互相比较。
    不依赖于考试,而主要靠工程师自己收集数据,然后分析,提高。
    PSP依赖于数据。
    PSP 的目的是记录工程师如何实现需求的效率

任务3:项目开发

  1. 项目背景:
    {0-1}背包问题:有N件物品和一个容量为M的背包。第i件物品所占空间是w[i],价值是v[i]。求解将哪些物品装入背包可使价值总和最大,对于每件物品,仅有取与不取两个状态。

  2. 需求分析:
    背包问题(Knapsack Problem,KP)是NP Complete问题,也是一个经典的组合优化问题,有着广泛而重要的应用背景。{0-1}背包问题({0-1 }Knapsack Problem,{0-1}KP)是最基本的KP问题形式,它的一般描述为:从若干具有价值系数与重量系数的物品(或项)中,选择若干个装入一个具有载重限制的背包,如何选择才能使装入物品的重量系数之和在不超过背包载重前提下价值系数之和达到最大。

  3. 设计实现
    该项目基本功能设计:

    • 正确读入实验数据文件的有效{0-1}KP数据;
    • 绘制任意一组{0-1}KP数据以价值重量为横轴、价值为纵轴的数据散点图;
    • 对一组{0-1}KP数据按重量比进行非递增排序;
    • 用户能够自主选择贪心算法、动态规划算法、回溯算法求解指定{0-1} KP数据的最优解和求解时间
    • 任意一组{0-1} KP数据的最优解、求解时间和解向量可保存为txt文件或导出EXCEL文件。
  4. 总结:你设计的程序如何实现软件设计的“模块化”原则
    模块化设计,顾名思义,一个系统有许多功能,每个功能由不同模块设计实现,通过对各个模块实现连接组成一个系统,修改与添加功能也会方便许多。在本次实验中,需要正确读入实验数据文件的有效{0-1}KP数据。用户可以自主的选择,贪心法,动态规划法,回溯法中的其中一种方法进行实现。所以要至少设置三个模块来实现这三种算法。

  5. 部分代码设计:

  • 散点图绘制部分的代码:
点击查看代码
private static class MyCanvas extends Canvas {

       //覆盖JPanel的paint方法
       // 画坐标轴,画点
       public void paint(Graphics g) {
           int i=1;
           int x;
           int y;
           Graphics2D g2 = (Graphics2D) g;// 调用新画图类Graphics2D(强制转化为Graphics2D这个类)
           g2.drawString(" 价值",50, 50);
           g2.drawString(" 重量",300, 300);
           g2.drawLine(50, 300, 300, 300);// 画一条线x轴
           g2.drawLine(50, 300, 50, 50);// 画一条线y轴
           while (i<=n) {
               //窗口400*400,按比例画散点图
               x = 50+array[i][0]*2;//价值
               y = 300-(array[i][1])*2;//重量
               g2.fillOval(x,y,5,5);    //画点
               i++;

           }
       }
   }
  • 运行时间计算部分代码:
点击查看代码
long startTime = System.nanoTime(); //获取开始时间
                Knapsack(v, w, c, m);
                traceback(m, w, c, x);
                System.out.println("可装入背包的物品的最大价值:" + m[0][c]);
                long endTime = System.nanoTime();//获取结束时间
                long allTime = (endTime - startTime);
                System.out.println("程序运行时间:" + allTime + "ns"); //输出程序运行时间
  • 排序算法:
点击查看代码
public static void sort(){
        Double[] r = new Double[n];  //保存性价比的数组
        int[] index = new int[n]; //保存按性价比排序的物品的下标
        //计算得到各个物品的性价比
        for (int i = 0; i < n; i++) {
            r[i] = (double) v[i] / w[i];
            index[i] = i;  //初始化各个物品的默认性价比排序
        }

        //对各个物品的性价比进行排序
        for (int i = 0; i < r.length - 1; i++) {
            for (int j = i + 1; j < r.length; j++) {
                if (r[i] < r[j]) {
                    double temp = r[i];
                    r[i] = r[j];
                    r[j] = temp;
                    //将排序后性价比的下标更新为性价比排序后的位置
                    int x = index[i];
                    index[i] = index[j];
                    index[j] = x;
                }
            }
        }

        //将排序好的重量和价值分别保存到数
        for (int i = 0; i < n; i++) {
            w1[i] = w[index[i]];
            v1[i] = v[index[i]];
            System.out.println("价值:"+ v1[i]+" 重量:"+w1[i] + " 性价比" + r[i]);
        }

    }
  1. 测试结果
    散点图绘制功能测试如下

    (第1组数据)

    (第7组数据)

    背包数据选择功能测试如下:

    使用第一组背包数据,三种算法测试结果如下:

    使用第一组背包数据,写入文件的数据如下:

  2. 代码规范:

    • 缩进:
      缩进为4个空格(使用Tab键)。
  • 变量命名:
    不以下划线或美元符号开始或结束;
    不使用拼音与英文混合的方式;
    方法名、参数名、成员变量、局部变量都使用lowerCamelCase风格,遵从驼峰形式。
  • 每行最多字符数:
    单行字符数限制不超过120个,超出需要换行,换行时遵循如下原则:
    • 第二行相对第一行缩进 4个空格,从第三行开始,不再继续缩进;
    • 运算符与下文一起换行;
    • 方法调用的点符号与下文一起换行;
    • 在多个参数超长,逗号后进行换行;
    • 括号前不换行。
  • 函数最大行数:
    函数的规模尽量限制在100行以内。
  • 函数命名:
    函数名用大写字母开头的单词组合而成。
  • 类命名:
    采用类驼峰形式,命名首字母可小写,
    异常类命名使用Exception结尾;
    测试类命名以它要测试的类的名称开始,以Test结尾。
  • 常量:
    常量命名全部大写,单词间用下划线隔开。
  • 空行规则:
    注释与其上面的代码用空行隔开;
    在每个类声明后、每个函数定义结束之后都要加空行;
    在一个函数体内,逻辑上密切相关的语句之间不加空行,其他地方应加空行分隔。
  • 注释规则:
    在源文件头部和函数头部进行注释;
    注释和代码同时更新,不用的注释删除;
    注释与所描述内容进行同样的缩排;
    注释掉的代码要配合相关说明;
    变量、常量、宏的注释应放在其上方相邻位置或右方。
  • 操作符前后空格:
    赋值运算符、逻辑运算符、加减乘除符号、三目运行符等二元操作符的左右必须加一个空格;
    一元操作符前后不加空格;
    中括号、点等这类操作符前后不加空格。
  1. PSP展示
PSP2.1 任务内容 计划完成所需要的时间(min) 实际完成所需要的时间(min)
Planning 计划 25 30
Estimate 估计需要的时间并规划步骤 30 25
Development 开发 200 280
Analysis 需求分析 70 110
Design Spec 生成设计文档 25 20
Design Review 设计复审 15 20
Coding Standard 代码规范 10 15
Design 具体设计 10 10
Coding 具体编码 80 120
Code Review 代码复审 70 70
Test 测试 30 20
Reporting 报告 120 110
Test Report 测试报告 30 30
Size Measurement 计算工作量 40 30
Postmortem & Process Improvement Plan 事后总结 ,并提出过程改进计划 35 30

任务4:完成任务3的程序开发,将项目源码的完整工程文件提交到你注册Github账号的项目仓库中

  • 代码已提交至GitHub

posted @ 2022-03-21 17:42  FIRE卡卡  阅读(94)  评论(2编辑  收藏  举报