201871010114-李岩松 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告
项目 | 内容 |
---|---|
课程班级博客链接 | https://edu.cnblogs.com/campus/xbsf/2018CST |
这个作业要求链接 | https://www.cnblogs.com/nwnu-daizh/p/14604444.html |
我的课程学习目标 | 掌Github中协同开发程序的操作 理解遗传算法 实现D{0-1}KP算法实验平台,并掌握结对项目当中的当中的设计规范、代码复审的方法 |
结对方学号-姓名 | 胡欢欢-201871010109 丁宣元-201871010106 |
结对方本次博客链接 | https://www.cnblogs.com/budinge/p/14575937.html https://www.cnblogs.com/budinge/p/14575937.html |
这个作业在哪些方面帮助我实现学习目标 | 克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》 核查表复审同伴项目代码并记录 用两人结对编程方式,设计开发一款D{0-1}KP 实例数据集算法实验平台 |
项目Github仓库地址 | https://github.com/budinge/Exercise-homework1.git |
任务1:阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念 |
-
代码风格规范:要是文字上的规定,看似表面文章,实际上非常重要,理解为代码在编码过程当中的语法规则要求。代码风格的原则是:简明,易读,无二义性(根据邹建老师的构建之法)
代码风格规范 常见规则 缩进 TAB键或四个空格 行宽 可以规定在80-100字符 括号 在复杂的条件表达式中,用括号清楚地表示逻辑优先级 断行与空白的{}行 要有确定的结构分析 分行 不要把多行语句放在一行上 -
代码设计规范: 牵扯到程序设计、模块之间的关系、设计模式等,比如函数的规定、错误的处理,类的设计。
-
代码复审:
代码是否在代码规范的框架内正确地解决了问题
代码复审的三种形式:自我复审、同伴复审、团队复审。目的是找出代码错误、发现逻辑错误、发现算法错误、发现潜在的错误和回归性错误、发现可能需要改进的地方、
传授经验;
代码复审后把记录整理出来:更正明显的错误、记录无法很快更正的错误、把所有的错误记在自己的一个“我常犯的错误”表中,作为以后自我复审的第一步。 -
结对编程:在结对编程模式下,一对程序员肩并肩地、平等地、互补地进行开发工作。两个程序员并排坐在一台电脑前,面对同一个显示器,使用同一个键盘,同一个鼠标一起工作。他们一起
分析,一起设计,一起写测试用例,一起编码,一起单元测试,一起集成测试,一起写文档等
任务2:两两自由结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价,具体要求如下:
- 对项目博文作业进行阅读并进行评论,评论要点包括:博文结构、博文内容、博文结构与PSP中“任务内容”列的关系、PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究,将以上评论内容发布到博客评论区。
- 克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。
代码复审记录:
复审项目 | 复审问题 | 复审结果 |
---|---|---|
概要部分 | 代码能符合需求和规格说明么? 代码设计是否有周全的考虑? 代码可读性如何? 代码容易维护么? 代码的每一行都执行并检查过了吗 |
代码未实现算法调用,博文中未找到规格说明文档 较为周全 较好 维护性较好 已完成 |
设计部分 | 设计是否遵从已知的设计模式或项目中常用的模式? 有没有硬编码或字符串/数字等存在? 代码有没有依赖于某一平台,是否会影响将来的移植? 开发者新写的代码能否用已有的Library/SDK/Framework中的功能实现? 在本项目中是否存在类似的功能可以调用而不用全部重新实现? 有没有无用的代码可以清除? |
遵循 存在文件名字符串存在 无依赖 无 排序功能 无 |
代码规范 | 修改的部分符合代码标准和风格么? | 符合 |
具体编码 | 有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常? 参数传递有无错误,字符串的长度是字节的长度还是字符(可能是单/双字节)的长度,是以0开始计数还是以1开始计数? 边界条件是如何处理的? Switch语句的Default是如何处理的? 循环有没有可能出现死循环?有没有使用断言(Assert)来保证我们认为不变的条件真的满足? 对资源的利用,是在哪里申请,在哪里释放的? 有没有可能导致资源泄露?有没有可能优化? 数据结构中是否有无用的元素? |
代码中无容错处理 没有检查返回值 未发现异常 没有使用switch语句 循环没有死循环 无断言存在 读取文件资源,无释放 无 |
效能 | 代码的效能(Performance)如何?最坏的情况是怎样的?代码中,特别是循环中是否有明显可优化的部分? 对于系统和网络调用是否会超时?如何处理? |
算法未实现,无法测试效能 在散点图中没有无代码优化 |
可测试性 | 代码是否需要更新或创建新的单元测试? | 暂时不需要 |
- 依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。
指令 | 功能 |
---|---|
Fork | 当选择 fork,相当于你自己有了一份原项目的拷贝,当然这个拷贝只是针对当时的项目文件,如果后续原项目文件发生改变,你必须通过其他的方式去同步 |
clone | 拷贝仓库中的源代码 |
Push | 提交本地仓库中修改的源代码到远程仓库 |
Pull request | 将自己复制fork后的代码,修改完成后,提交给父分支 |
Merge Pull request | 审核修改后的代码,并进行合并 |
fork对方项目并进行修改 | |
clone对方项目 | |
任务3: |
- 代码编写规范:
已提交到项目Github仓库
- 需求分析
对于本次项目设计,主要用户群体是针对与学生来进行测评,此系统需要具备如下功能
1.基本的折扣背包问题求解页面,用户提交需要绘制那几组数组,那个文件,下方展示出绘制的散点图
2.按照分组背包问题中第三组的价值比重量排序,用户提交的是文件名和组数,页面下方展示排序结果
3.固定的算法求解,算法求解功能,用户选择求解的数据(组数和文件名)背包最大容量,以及动态规划和回溯算法求解功能
4.文件保存,对于每一次求解均可实现查看每次文件保存的结果,可以在线浏览文件,打开求解结果
5.算法嵌入测评,用户可以将自己的代码动态嵌入到编辑器中,选择测评的数据和编程语言,提交后可以得到测评结果 - 技术说明:
前端技术说明:
后端技术说明:
- 功能实现
1.绘制散点图
2.算法求解
3.动态算法求解
4.数据库存储:
5.排序实现:
6.遗传算法
本次博客中遗传算法的学习链接:
https://www.jianshu.com/p/ae5157c26af9
# coding=utf-8
import random
#背包问题
# 物品 重量 价格
#终止界限
FINISHED_LIMIT = 5
#重量界限
WEIGHT_LIMIT = 80
#染色体长度
CHROMOSOME_SIZE = 6
#遴选次数
SELECT_NUMBER = 4
max_last = 0
diff_last = 10000
#判断退出
def is_finished(fitnesses):
global max_last
global diff_last
max_current = 0
for v in fitnesses:
if v[1] > max_current:
max_current = v[1]
print 'max_current:',max_current # 得到当前最大的价值
diff = max_current - max_last # 价值差,也就是适应度的改变的大小
# 这里判断连续两代的改变量如果都小于5,则停止迭代
if diff < FINISHED_LIMIT and diff_last < FINISHED_LIMIT:
return True
else:
diff_last = diff
max_last = max_current
return False
#初始染色体样态
def init():
chromosome_state1 = '100100'
chromosome_state2 = '101010'
chromosome_state3 = '010101'
chromosome_state4 = '101011'
chromosome_states = [chromosome_state1,
chromosome_state2,
chromosome_state3,
chromosome_state4]
return chromosome_states
#计算适应度
def fitness(chromosome_states):
fitnesses = []
for chromosome_state in chromosome_states: # 遍历所有的染色体
value_sum = 0 # 物品重量
weight_sum = 0 # 物品价值
# 将一个可遍历的数据对象组合为一个索引序列,同时列出数据和数据下标
for i, v in enumerate(chromosome_state):
# 对染色体中的1,即存在的物品体重和价格求和
if int(v) == 1:
weight_sum += X[i + 1][0]
value_sum += X[i + 1][1]
fitnesses.append([value_sum, weight_sum])
return fitnesses
#筛选
def filter(chromosome_states, fitnesses):
#重量大于80的被淘汰
index = len(fitnesses) - 1
while index >= 0:
index -= 1
if fitnesses[index][1] > WEIGHT_LIMIT:
chromosome_states.pop(index) # 弹出不符合条件的染色体
fitnesses.pop(index) # 弹出不符合条件的适应度
#print chromosome_states,'\n',fitnesses
#遴选
selected_index = [0] * len(chromosome_states) # 如果[0]*3得到的是[0,0,0]
for i in range(SELECT_NUMBER):
# 随机选择染色体,然后得到相应的索引
j = chromosome_states.index(random.choice(chromosome_states))
selected_index[j] += 1
return selected_index
# 交叉产生下一代
def crossover(chromosome_states, selected_index):
chromosome_states_new = []
index = len(chromosome_states) - 1
#print 'index:',index
while index >= 0: # 遍历完所有的染色体组的染色体(其中下标-1代表最后一个染色体的索引)
print 'index:',index
index -= 1
chromosome_state = chromosome_states.pop(index)
print 'chromosome_states_3:',chromosome_states # 弹出后的染色体组
print 'chromosome_state:',chromosome_state # 弹出的染色体
for i in range(selected_index[index]):
chromosome_state_x = random.choice(chromosome_states) # 随机选择一个染色体
print 'chromosome_state_x:',chromosome_state_x
pos = random.choice(range(1, CHROMOSOME_SIZE - 1)) # 随机[1, 2, 3, 4]其中的一个数
print 'pos:',pos
chromosome_states_new.append(chromosome_state[:pos] + chromosome_state_x[pos:])
print 'chromosome_states_new:',chromosome_states_new
chromosome_states.insert(index, chromosome_state) # 恢复原染色体组
print 'chromosome_states_4:', chromosome_states
return chromosome_states_new # 返回得到的新的染色体组
if __name__ == '__main__':
# 初始群体
chromosome_states = init() # 是全局的
print 'chromosome_states:',chromosome_states
n = 100 # 迭代次数
while n > 0:
n -= 1
#适应度计算
fitnesses = fitness(chromosome_states)
#print 'fitnesses:',fitnesses
if is_finished(fitnesses):
break # 如果符合条件,立刻停止循环
print '1:', fitnesses
#遴选
selected_index = filter(chromosome_states, fitnesses)
print '2:', selected_index
print 'chromosome_states_2:',chromosome_states
#产生下一代
chromosome_states = crossover(chromosome_states, selected_index)
print '3:', chromosome_states
print str(n)+'..................................' # 迭代次数
fitnesses = fitness(chromosome_states)
print 'fitnesses:',fitnesses
print chromosome_states
6.开发过程提交记录
7.主要代码
<?php
/* +----------------------------------------------------------------------
* 作 者: liyansong <1559393325@qq.com>
+----------------------------------------------------------------------
* 创建日期:2021-04-09
+----------------------------------------------------------------------
* 文件描述:算法求解,排序嵌入、算法排序
+----------------------------------------------------------------------
* 升级记录:
+----------------------------------------------------------------------
*/
class IndexAction extends CommonAction {
public function index() {
$this->display();
}
public function sort()
{
$this->display();
}
public function sortResult()
{
$data['fileName'] = $_REQUEST['fileName'];
$data['seriesNumber'] = (int)$_REQUEST['seriesNumber'];
$url = 'http://127.0.0.1:5000/sort';
$return = $this->posturl($url, $data);
$len=count($return,COUNT_NORMAL);
for($i=0;$i<$len;$i++)
{
$str[$i]=str_ireplace(array('{','\'','}','p1','p2','p3',':','pw1','pw2','pw3','w1','w2','w3'), array('', '','','','','','','','',''), $return[$i]);
$result[$i]=explode(",",$str[$i]);
}
if (Null != $return)
{
$this->assign('result_data',$result);
$this->display('sort');
}
else
{
$this->error('排序失败',__APP__ . '?g=Index&m=Index&a=sort');
}
}
function posturl($url,$data){
ini_set('max_execution_time',0);
$data = json_encode($data);
$headerArray = array("Content-type:application/json;charset='utf-8'","Accept:application/json");
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,FALSE);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl,CURLOPT_HTTPHEADER,$headerArray);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return json_decode($output,true);
}
public function scatter() {
header("Cache-Control: no-cache, must-revalidate");
$data['fileName'] = $_REQUEST['fileName'];
$data['seriesNumber'] = (int)$_REQUEST['seriesNumber'];
$url = 'http://127.0.0.1:5000/';
$pic_url='http://127.0.0.1:5000/static/1.png';
$return=$this->posturl($url,$data);
$this->assign('pic_url',$pic_url);
$this->display();
}
public function salve() {
$this->display();
}
public function salveResult()
{
$data['fileName'] = $_REQUEST['fileName'];
$data['seriesNumber'] = (int)$_REQUEST['seriesNumber'];
$data['maxWeight'] = (int)$_REQUEST['maxWeight'];
if (Null == $data['maxWeight'])
{
$this->error('背包的最大重量未填',__APP__ . '?g=Index&m=Index&a=salve');
}
$url_flashBack = 'http://127.0.0.1:5000/flashBack';
$url_dp = 'http://127.0.0.1:5000/dp';
if ($_REQUEST['salve_function'] == flashback) {
$flashBack_result = $this->posturl($url_flashBack, $data);
$this->assign('salveResult',$flashBack_result);
$this->display('salve');
} else {
$dp_result = $this->posturl($url_dp, $data);
$this->assign('salveResult',$dp_result);
$this->display('salve');
}
}
public function dp(){
}
public function check(){
$this->display();
}
public function checkResult(){
$data['fileName'] = $_REQUEST['fileName'];
$data['seriesNumber'] = (int)$_REQUEST['seriesNumber'];
$data['maxWeight'] = (int)$_REQUEST['maxWeight'];
$data['fileType'] =$_REQUEST['fileType'];
$data['value']=$_REQUEST['value'];
if (Null == $data['maxWeight'])
{
$this->error('背包的最大重量未填',__APP__ . '?g=Index&m=Index&a=check');
}
if (Null == $data['value'])
{
$this->error('运行错误',__APP__ . '?g=Index&m=Index&a=check');
}
$url = 'http://brp964.natappfree.cc/upload';
$salve_return=$this->posturl($url,$data);
dump($salve_return);
$this->assign('salve_return',$salve_return);
$this->display('check');
}
}
?>
结对编程讨论:
本次项目PSP:
软件设计说明:
本次项目设计主要采用前后端分离的MMVC的开发模式,前台使用AmazeUI前端框架+ThinkPHP3.1.3框架,后台去调用Pyton接口,在后台主要使用flask框架+MySQL进行后台接口的框架,本次开发过程当中实现了在线绘制散点图、回溯算法求解、动态算法求求解、数组排序、算法动态嵌入求解测评功能,后台分别有五个接口分别对前台传过来的数据进行处理并返回json字符串,与此同时本系统还记录了开发过程当中的开发日志,以及更新状态,界面为自适应界面手机和PC端均可使用,采用接口技术更为以后的微信小程序和APP开发提供了便捷指出
结对编程体验:
在本次结对编程当中,深刻体会到了结对编程带来的好处,我们进行线上讨论交流,调试代码,在整个过程当中出现了很多新奇的想法比如在讨论过程当中提出是否能够实现自适应呢让学生拿着手机也能测评自己的代码,提出了新的用户需求,而且在整个过程当中结对编程对象在轮换检查对方编码的错误和接口之间的对接很好的提高的了开发效率,最让人体验深刻的还是在有争吵的时候汉堡包法真的提供了很大的解决方法,有意见有分歧,在起初开发的过程当中就避免了很多的错误,很好的实现了1+1+1>3的整个项目