201871030110-何飞 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告
项目 | 内容 |
---|---|
课程班级博客链接 | 班级博客 |
这个作业要求链接 | 作业要求 |
我的课程学习目标 | 1.体会团队项目的开发流程,吸收他人开发经验。 2.熟悉并学会构建实验折扣0-1背包问题的实验平台。 3.熟练运用springboot+layui技术 |
这个作业在哪些方面帮助我实现学习目标 | 1.学会了echarts图表的使用。 2.熟练使用springboot+layui技术。 |
结对方学号-姓名 | 201871010130-周学铭 |
结对方本次博客作业链接 | 结对方博客 |
本项目Github的仓库链接地址 | GitHub仓库链接 |
任务一
阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念
通过阅读构建之法,掌握了代码风格、设计规范、代码复审、结对编程等概念。同时对结对编程有了进一步的体验,能够进行项目的合理化编程,对企业级协同编程有了更加深入的了解。
任务二
两两*结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价.
结对方实验二博客链接地址:结对方博客地址
结对方Github项目仓库链接:结对方Github项目仓库地址
结对方项目克隆至本地后,阅读该项目,该项目算法运用合理,代码符合规范。
结对方实验二在我的知识体系领域内,没有什么大的问题,不需要进行修改。
任务三
-
需求分析陈述
- 折扣0-1背包问题是较为经典的NP问题之一,一方面:现今世界的有些问题与折扣0-1背包问题是分不开的,例如折扣销售问题、捆绑销售问题,之后就是这些经典的算法的一个个实例;另一边折扣0-1背包问题是学生学习NP完全问题,巩固上学期的算法设计这门课的有效途径之一,因此本次推出折扣0-1背包问题的实验平台。
-
软件设计说明
- 对于前端界面的设计说明:本次实验,采用的是Springboot+layui实现。
- 我主要负责的是前端GUI的渲染,同时与后端约定接口,后端的路由转发以及数据库的操作和算法的实现均由结对伙伴完成。
- 前端的GUI使用的是layui的框架,前端界面的显示是通过layui提供的模板,以及themeleaf、js等要素构成。themeleaf提供了强大的模板支持,本次实验中,themeleaf出演的角色是抽取公共的核心的DOM元素,在其它的前端页面通过调用的方式进行插入DOM节点,大大节约了开发的成本,提高了代码的可重用性;而layui主要是提供各种各样的优化的按钮、文本等之类的组件。(layui是国人构建的一个前端框架,由于开发者是做后端的程序员,所以,layui提供的接口是与后端进行了无缝衔接,同时,它通过简单的定制,便可使得页面渲染的效果极佳)。
- layui前端元素的显示是通过设置其class属性,达到显示元素的效果较为美观,通过layui封装的js,即可实现数据的异步传输(常见的网络通信有AJAX、axios、表单等,其中,前两项属于异步通信),它接收的服务器返回的参数必须是JSON格式,因此,它的js文件可能封装了AJAX,它要求后端返回的json数据必须是数组格式(key为data)、数据的长度(key为count)、数据的额外信息(key为msg)、数据成功与否(key为code),数据域(data为json对象或者hashmap)。layui的封装的js用于请求后台的数据,并显示在界面上(layui是通过模块化加载的,因此,需要引入响应的模块)。
- 本次项目的前端需要引用的js文件是通过cdn去加载的,因此,项目的运行需要在网络允许的范围内才能使用。
- 后台的处理主要由结对伙伴完成,后台主要处理三件事情。一是路由的问题,二是数据的加载与显示,三是算法。路由问题:主要是通过controller进行处理和转发,只需要将路径写对即可;数据的加载与显示,主要是通过从数据库中获取数据,构造json对象,返回到前端即可,需要注意的是,所有的服务器返回的数据必须是键值对的形式,最好是json(json只是键值对的一种,比如hashmap也是键值对的形式);对于算法,这一部分主要是结对伙伴在研究,我没有参与多少,主要由结对伙伴负责。
- 算法说明
- 算法介绍:是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。该算法通过数学的方式,利用计算机仿真运算,将问题的求解过程转换成类似生物进化中的染色体基因的交叉、变异等过程。是一种近似算法。
- 算法流程:
- 种群初始化:通过随机函数为初始种群赋初值。即用一长串的01串来表示种群的选择,1:选了该组数据;0:不选该组数据,所以我们可以生成一个随机数,然后对它进行去模来进行初始化。
- 个体评价:计算初始化种群适应度,首先对每个染色体其初值进行遍历,因为这里是按组为单位的,每组数据下面还有三种选择,所以需要对这三种选择继续进行随机选择。需要注意的是因为这三种选择概率不同,所以对它们赋值的概率也不同。同时在进行选择的时候,还要对背包的约束条件进行判断,即是否超出了背包初始的容积。最后返回当前的最优值并累积种群中各个个体的累积概率。
- 选择运算:这里使用的是赌轮选择策略,其依据是上一步中各种群中各个个体的累积概率。
- 交叉运算:这里仍然需要使用随机数,使用的方法为:两点交叉算子。
- 变异运算:依旧需要随机函数,但使用的方法为:多次对换变异算子。
-
程序实现及核心代码说明
前端代码主要是些界面渲染、js的处理等,后端代码主要是controller处理和返回服务器的请求参数。
-
前端较为核心的代码:
//引入公共的dom片段
<div th:insert="~{index::top}"></div>
<div th:insert="~{index::left}"></div>-
//js代码请求后台数据
layui.use('table',function() {
var table = layui.table; //第一个实例
table.render({
elem: '#tableShow',
url: '/selectFile', //数据接口
page: true, //开启分页
cols:[
[{field:'aa',type:"checkbox"},//设置复选框
{field:'id',title:'序号',type:"numbers"},
{field:'filename', title: '文件名', }]
],
toolbar:'#toolBarTable'
});
table.on('toolbar(testTable)',function (obj) {
var checkStatus = table.checkStatus(obj.config.id);
var arrLength = checkStatus.data.length;
if (arrLength>1){
layer.msg("您只能选择一条数据,请重新勾选");
}else if(arrLength==0) {
layer.msg("您必须选择一个文件");
}else{
layer.prompt({
formType: 1,
value: '1',
title: '请输入查看的组数(1-10)',
}, function(value, index, elem){
layer.close(index);
value=parseInt(value);
if (value>=1&&value<=10) {//在数据表格中添加数据
var filename = checkStatus.data[0].filename;
table.render({
elem: '#tableGroup',
url: '/selectOneGroup/' + filename + '/' + value,
page: true,//开启分页
cols: [
[{field: 'aa', type: "checkbox",align:'center'},//设置复选框
{field: 'id', title: '序号', type: "numbers",align:'center'},
{field: 'group', title: '数据项编号',align:'center'},
{field:'rate',title: "价值重量比",sort:true,width:200,align:'center'},
{field: 'profit1', title: '价值(一)',align:'center'},
{field: 'weight1', title: '重量(一)',align:'center'},
{field: 'profit2', title: '价值(二)',align:'center'},
{field: 'weight2', title: '重量(二)',align:'center'},
{field: 'profit3', title: '价值(三)',align:'center'},
{field: 'weight3', title: '重量(三)',align:'center'}]
]
});
layer.msg("单击即可自动进行排序");
} else{
layer.msg("请输入1-10的任意一个数字");
}
});
}
});
});- 注意:themleaf对于[[]]有严格的要求,但是这里需要的参数正好是[[]],因此,这里的参数需要进行适当的换行
-
后端较为核心的代码:
# 数据库的配置文件
spring:
datasource:
username: root
password: a1b2c3
url: jdbc:mysql://localhost:3306/experiment?serverTimezone=GMT&useUnicode=true&characterEncoding=utf-8
driverClassName: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource #连接池属性
initial-size: 15
max-active: 100
min-idle: 15
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
test-on-borrow: false
test-on-return: false
test-while-idle: true
validation-query: SELECT 1
validation-query-timeout: 1000
keep-alive: true
remove-abandoned: true
remove-abandoned-timeout: 180
log-abandoned: true
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
filters: stat,wall,slf4j
use-global-data-source-stat: true
preparedStatement: true
maxOpenPreparedStatements: 100
connect-properties.mergeSql: true
connect-properties.slowSqlMillis: 5000//服务器返回参数
@RequestMapping("/selectGroup/{filename}")//同时传递参数,用于指定显示的文件的组数
public String selectGroup(@PathVariable String filename) throws SQLException {
JSONObject json=new JSONObject();
//查询数据库,获取键值对,与前端接口相呼应
Connection connection = JDBCUtils.getConnection();
Statement statement = connection.createStatement();
String query="SELECT * FROM `knapsack` WHERE `filename`='"+filename+"'";
ResultSet rs = statement.executeQuery(query);
JSONArray array=new JSONArray();
while(rs.next()){
JSONObject object=new JSONObject();
object.put("dimension",rs.getString("dimension"));
object.put("cubage",rs.getString("cubage"));
object.put("group",rs.getString("group"));
object.put("profit",rs.getString("profit"));
object.put("weight",rs.getString("weight"));
array.put(object);
}
json.put("data",array);
json.put("code",0);
json.put("msg","");
json.put("count",array.length());
JDBCUtils.release(rs,statement,connection);
JDBCUtils.recordJournal("选择文件中分组","查询操作");
return json.toString();
} //路由转发
@RequestMapping("/index")
public String hello() throws SQLException {
JDBCUtils.recordJournal("路由转发","getIndex");
return "index";
}以上代码比较简单,没有什么解释的必要性。
-
描述结对的过程
- 截图显示讨论过程:
- 截图显示讨论过程:
PSP
PSP2.1 | 任务内容 | 计划完成需要的时间(min) | 实际完成需要的时间(min) |
---|---|---|---|
Planning | 计划 | 60 | 60 |
· Estimate | · 估计这个任务需要多少时间,并规划大致工作步骤 | 60 | 60 |
Development | 开发 | 2340 | 2580 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 60 |
· Design Spec | · 生成设计文档 | 30 | 30 |
· Design Review | · 设计复审 (和同事审核设计文档) | 60 | 60 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
· Design | · 具体设计 | 60 | 60 |
· Coding | · 具体编码 | 1800 | 2040 |
· Code Review | · 代码复审 | 180 | 120 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 180 |
Reporting | 报告 | 210 | 210 |
· Test Report | · 测试报告 | 60 | 60 |
· Size Measurement | · 计算工作量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结 ,并提出过程改进计划 | 120 | 120 |
- 小结感受
- 通过本次结对项目,感受到了结对编程的好处,同时,应当值得提出的是,结对编程应当注重接口的定义,前后端的交互,接口如果不合适,数据就无法加载。
附:程序运行结果图:
- 折扣0-1背包问题主界面
折扣0-1背包问题选择文件上传至数据库
折扣0-1背包问题文件已经选择
折扣0-1背包问题准备从数据库中已有文件中选取一组数据进行显示
折扣0-1背包问题显示某一组的数据
折扣0-1背包问题选组
折扣0-1背包问题绘制散点图
折扣0-1背包问题动态规划算法求解
折扣0-1背包问题遗传算法求解
折扣0-1背包问题日志信息显示
注:由于折扣0-1背包问题的回溯算法和动态规划算法基本上一致,故不展示截图