201971010117-刘春丽 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告
实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》
项目 | 内容 |
---|---|
课程班级博客链接 | 班级博客 |
这个作业要求链接 | 实验三 |
我的课程学习目标 | 1.体验软件项目开发中的两人合作,练习结对编程(Pair programming) 2.掌握Github协作开发程序的操作方法 |
这个作业在哪些方面帮助我实现学习目标 | (1)在程序设计方面提高了自己的编程能力; (2)让我了解了团队协作、分工的重要性; (3)结对编程、和同伴如何分工以及与同伴如何更好的交流。 |
结对方学号-姓名 | 201971010125-李涛 |
结对方本次博客作业链接 | 结对方本次博客作业 |
本项目Github的仓库链接地址 | 仓库地址 |
任务1:阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念;
-
代码风格规范:
- 主要是文字上的规定。代码风格的原则是:简明、易读、无二义性,包括对于缩进、行宽、括号、分行、命名、下划线、注释、大小写以及断行与空白的{}行的处理;
- 缩进
- 在学习之前习惯性理解为:对于缩进Tab键是最好的方式,也是最简单的,不用一个空格一个空格的敲,这样的习惯主要是因为大一学习C语言和WEB前端设计养成的。对于Tab键在不同的情况下会显示不同的长度的情况其实在去年学习Linux操作系统的时候用文件编写C语言程序时,就是使用Tab键来规范缩进的,那时很明显Tab键的长度和我之前在Windows系统下写代码时的长度不一样,显示长度为8个空格长度。
- 命名
- 字母,数字,下划线组成由字母,下划线开头不能有二义性,有长度要求。
- 注释
- 修改代码时注释,变量声明时注释。
- 缩进
- 主要是文字上的规定。代码风格的原则是:简明、易读、无二义性,包括对于缩进、行宽、括号、分行、命名、下划线、注释、大小写以及断行与空白的{}行的处理;
-
代码设计规范:
- 牵扯到程序设计、模块之间的关系、设计模式等。比如针对函数,他的最重要的原则就是:只做一件事,并且要做好。可以使用goto实现单一的出口。还有错误处理方面的一些内容,比如断言的正确使用等规范。
-
代码复审:
- 看代码是否在代码规范的框架内正确地解决了问题。代码复审的三种形式:自我复审、同伴复审、团队复审。
自我复审 | 自己VS.自己 | 用同伴复审的标准来要求自己。不一定最有效,因为开发者对自己总是过于自信。如果能持之以恒,则对个人有很大好处 |
同伴复审 | 复审者VS.开发者 | 简便易行 |
团队复审 | 团队VS.开发者 | 有比较严格的规定和流程,用于关键的代码,以及复审后不再更新的代码。覆盖率高——有很多双眼睛盯着程序。但是有可能效率不高(全体人员都要到会) |
- 结对编程:
- 在结对编程模式下,一对程序员肩并肩地、平等地、互补地进行开发工作。两个程序员并排坐在一台电脑前,面对同一个显示器,使用同一个键盘,同一个鼠标一起工作。他们一起分析,一起设计,一起写测试用例,一起编码,一起单元测试,一起集成测试,一起写文档等。
任务2:两两自由结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价,具体要求如下:
1. 对项目博文作业进行阅读并进行评论,评论要点包括:博文结构、博文内容、博文结构与PSP中“任务内容”列的关系、PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究,将以上评论内容发布到博客评论区。
2. 克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。
- 克隆结对方项目源码到本地机器
- 克隆时一直报错,上网浏览之后才发现要更新DNS缓存,这才解决了该问题:
-
阅读并测试对方的代码截图如下:
-
散点图结果如下图:
-
多算法选择如下图:
-
文件保存如下图:
-
-
参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录如下:
概要部分 | |
代码符合需求和规格说明么? | 代码基本符合需求和规格说明 |
代码设计是否考虑周全? | 代码设计有周全的考虑 |
代码可读性如何? | 代码可读性还不错 |
代码容易维护么? | 代码容易维护 |
代码的每一行都执行并检查过了吗? | 代码的每一行都执行并检查过了 |
设计规范部分 | |
设计是否遵从已知的设计模式或项目中常用的模式? | 代码遵从已知的设计模式或项目中常用的模式 |
代码有没有依赖于某一平台,是否会影响将来的移植(如Win32到Win64)? | 代码没有依赖于某一平台,不会影响将来的移植 |
开发者新写的代码能否用已有的Library/SDK/Framework中的功能实现? 在本项目中是否存在类似的功能可以调用? |
代码基本能用已有的Library/SDK/Framework中的功能实现 |
有没有无用的代码可以清除? | 没有无用的代码可以清除 |
修改的部分代码符合标准和风格吗? | 符合标准和风格 |
具体代码部分 | |
有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常? | 对所出现的错误进行了修改,对于调用的外部函数检查了返回值并且处理了异常 |
参数传递有无错误,字符串的长度是字节还是字符的长度? 是以0开始计数还是以1开始计数? |
参数传递无误,字符串的长度是字节的长度,是以0开始计数的 |
边界条件是如何处理的?switch语句的default分支是如何处理的?循环有没有可能出现死循环? | switch语句的default分支返回false,没有出现死循环。 |
有没有使用断言(Assert)来保证我们认为不变的条件真的得到满足? | 无。 |
对资源的利用是在哪里申请的, 在哪里释放的?有没有可能导致资源泄露?有没有优化的空间? | 都在内存中完成,很有可能泄露 |
数据结构中有没有用不到的元素? | 无,整体比较简洁 |
效能 | |
代码的效能(Performance)如何?最坏的情况如何? | 达到了具体任务的要求。 |
代码中,特别是循环中是否有明显可优化的部分? | 有 |
对于系统和网络调用是否会超时?如何处理? | 未出现超时现象 |
可读性 | |
代码可读性如何?有没有足够的注释? | 可读性较强,有足够的注释 |
可测试性 | |
代码是否需要更新或创建新的单元测试? | 可以接着开发,增加更多的功能 |
3. 依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。
-
Fork:将别人发布的项目复制,相当于一个分支;项目复制到自己的github中,于是本地就有了一个仓库。
-
Clone:从自己的github上把fork过来的项目复制到本地,这样本地就有了一个项目。在本地新建一个MyGit文件夹,将项目文件clone到该文件夹。
-
Push:将本地项目进行修改开发后,同步到你的github上的仓库中。
-
Pull request:把自己github中的已经修改的内容申请同步到最初那个开发者的项目中。
-
Merge pull request:最初的开发者同意你的修改,将其合并到自己的项目中。
任务3:采用两人结对编程方式,设计开发一款{0-1}KP 实例数据集算法实验平台
1、实现如下功能:
(1)平台基础功能:实验二 任务3;
(2){0-1}KP 实例数据集需存储在数据库;
(3)平台可动态嵌入任何一个有效的{0-1}KP 实例求解算法,并保存算法实验日志数据;
(4)人机交互界面要求为GUI界面(WEB页面、APP页面都可);
(5)查阅资料,设计遗传算法求解{0-1}KP,并利用此算法测试要求(3);
(6)附加功能:除(1)-(5)外的任意有效平台功能实现。
2、需求分析
- Who 为谁设计,用户是谁?
- 设计开发一款{0-1}KP 实例数据集算法实验平台 ,提供给使用不同方法求解0-1背包,且处理多组数据的用户。 - What 需要解决如下问题?
- 数据读入:
正确读入实验数据文件的有效{0-1}KP数据; - 绘制散点图:
绘制任意一组{0-1}KP数据以价值重量为横轴、价值为纵轴的数据散点图; - 排序:
对一组{0-1}KP数据按重量比进行非递增排序; - 多算法选择求解:
能够自主选择贪心算法、动态规划算法、回溯算法求解指定{0-1} KP数据的最优解和求解时间(以秒为单位); - 文件保存:
任意一组{0-1} KP数据的最优解、求解时间和解向量可保存为txt文件或导出EXCEL文件; - 存储数据库:
{0-1}KP 实例数据集需存储在数据库; - 使用人机交互页面:
人机交互界面要求为GUI界面(WEB页面、APP页面都可); - 遗传算法求解:
查阅资料,设计遗传算法求解{0-1}KP,并利用此算法测试要求平台可动态嵌入任何一个有效的{0-1}KP 实例求解算法,并保存算法实验日志数据;
- 数据读入:
- Why 为什么解决这些问题?
- 根据题目要求,实现完整的项目,提高学生的编程水平;结对编程,让我们平等地,互补地进行开发工作。
3、功能设计
4、设计实现
- 函数之间的调用:选用不同的模块,调用相应的函数。
5、主要代码
- 核心代码
点击查看代码
# 创建数据库
def CreateDataBase(self):
global i
global d
global cubage # 背包最大容量
global profit # 物品价值
global weight # 物品重量
global pw # 物品价值/重量比
# 连接到SQLite数据库,数据库文件是mrsoft.db
conn = sqlite3.connect('mrsoft.db')
cursor = conn.cursor()
# 如果表已经存在则删除
cursor.execute('DROP TABLE IF EXISTS user')
# 如果表不存在则创建表
cursor.execute('create table if not exists user (num int(10) primary key,profit int(20), weight int(20))')
cubage[i] = max(list(map(int,re.findall(r'\d+',line[i*8+3]))))
profit[i] = list(map(int,re.findall(r'\d+',line[i*8+5])))
weight[i] = list(map(int,re.findall(r'\d+',line[i*8+7])))
pw[i] = list(map(lambda x:x[0]/x[1],zip(profit[i],weight[i])))
# 往表中插入数据
for j in range(0,d):
cursor.execute('insert into user (num,profit,weight) values ("%d","%d","%d")'%(j,profit[i][j],weight[i][j]))
cursor.execute('select * from user')
result=cursor.fetchall()
# 关闭游标
cursor.close()
# 提交事务
conn.commit()
# 关闭Connection
conn.close()
return result
点击查看代码
class MyFrame3(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, '有效数据', size=(800, 800))
# 遗传算法
start2 = time.perf_counter()
heigh = heigh+70
m = 32 # 规模
N = 500 # 迭代次数
Pc = 0.8 # 交配概率
Pm = 0.05 # 变异概率
V =profit[i] # 物品价值
W =weight[i] # 物品重量
n = len(W) # 染色体长度
w = cubage[i] # 背包最大容量
C = self.init(m, n)
S,F = self.fitness(C,m,n,W,V,w)
B ,y = self.best_x(F,S,m)
Y =[y]
for i in range(N):
p = self.rate(F)
C = self.chose(p, C, m, n)
C = self.match(C, m, n, Pc)
C = self.vari(C, m, n, Pm)
S, F = self.fitness(C, m, n, W, V, w)
B1, y1 = self.best_x(F, S, m)
if y1 > y:
y = y1
Y.append(y)
wx.StaticText(self.panel,label='遗传算法:', pos=(500,heigh))
heigh = heigh+30
wx.StaticText(self.panel,label='最大价值为:%d'%(y), pos=(500,heigh))
# 初始化,N为种群规模,n为染色体长度
def init(self,N,n):
C = []
for i in range(N):
c = []
for j in range(n):
a = np.random.randint(0,2)
c.append(a)
C.append(c)
return C
# 评估函数
# x(i)取值为1表示被选中,取值为0表示未被选中
# w(i)表示各个分量的重量,v(i)表示各个分量的价值,w表示最大承受重量
def fitness(self,C,N,n,W,V,w):
S = [] # 用于存储被选中的下标
F = [] # 用于存放当前该个体的最大价值
for i in range(N):
s = []
h = 0 # 重量
f = 0 # 价值
for j in range(n):
if C[i][j]==1:
if h+W[j]<=w:
h=h+W[j]
f = f+V[j]
s.append(j)
S.append(s)
F.append(f)
return S,F
# 适应值函数,B位返回的种族的基因下标,y为返回的最大值
def best_x(self,F,S,N):
y = 0
x = 0
B = [0]*N
for i in range(N):
if y<F[i]:
x = i
y = F[x]
B = S[x]
return B,y
# 计算比率
def rate(self,x):
p = [0] * len(x)
s = 0
for i in x:
s += i
for i in range(len(x)):
p[i] = x[i] / s
return p
# 选择
def chose(self,p, X, m, n):
X1 = X
r = np.random.rand(m)
for i in range(m):
k = 0
for j in range(n):
k = k + p[j]
if r[i] <= k:
X1[i] = X[j]
break
return X1
# 交配
def match(self,X, m, n, p):
r = np.random.rand(m)
k = [0] * m
for i in range(m):
if r[i] < p:
k[i] = 1
u = v = 0
k[0] = k[0] = 0
for i in range(m):
if k[i]:
if k[u] == 0:
u = i
elif k[v] == 0:
v = i
if k[u] and k[v]:
# print(u,v)
q = np.random.randint(n - 1)
# print(q)
for i in range(q + 1, n):
X[u][i], X[v][i] = X[v][i], X[u][i]
k[u] = 0
k[v] = 0
return X
# 变异
def vari(self,X, m, n, p):
for i in range(m):
for j in range(n):
q = np.random.rand()
if q < p:
X[i][j] = np.random.randint(0,2)
return X
6、测试运行
-
程序运行
-
选择要读取的文件:
-
选择要文件中要读取哪一组数据:
-
读取到的数据存入数据库:
-
散点图的显示:
-
遗传算法运行结果(需要注意的是:遗传算法是一种近似最优化算法,它的每个解都是近似最优解,不能保证是全局最优。):
-
有效数据的展示,其中包含选定数据的价值重量、第三项价值:重量比的排序、利用动态规划算法、遗传算法求解指定D{0-1} KP数据的最优解和求解时间(以秒为单位):
-
结果存储至txt中:
7、描述结对的过程,提供两人在讨论、细化和编程时的结对照片
-
因为都在一个宿舍,所以聚集在一起来共同完成这个项目是比较方便的,并且比较熟悉,在沟通方面也是顺畅的。最开始是一起分析确定了项目要实现哪一些功能,GUI界面如何呈现,各类功能如何嵌入GUI界面,选择什么语言来编程,大概的方向确定好之后,就开始着手写代码。在编程的过程中,两个人轮流编程,一人编程的时候,另一人帮忙查资料,检查代码中是否有错误,提醒修改,遇到麻烦的地方,两个人一起思考、商量解决办法。
- 此次作业的PSP
PSP2.1 | 任务内容 | 计划共完成需要的时间(h) | 实际完成需要的时间(h) |
---|---|---|---|
Planning | 计划 | 0.5 | 0.5 |
Estimate | 估计这个任务需要多长时间, 并规划大致工作步骤 |
0.5 | 0.5 |
Development | 开发 | 45.5 | 57 |
Analysis | 需求分析(包括学习新技术) | 15 | 16 |
Design Spec | 生成设计文档 | 1 | 0.5 |
Design Review | 设计复审 | 1 | 1.5 |
Coding Standard | 代码规范 | 1 | 1 |
Design | 具体设计 | 0.5 | 0.5 |
Coding | 具体编码 | 25 | 34 |
Code Review | 代码复审 | 1 | 0.5 |
Test | 测试 | 2 | 3 |
Reporting | 报告 | 2 | 2.7 |
Test Report | 测试报告 | 1 | 1.5 |
Size Measurement | 计算工作量 | 0.5 | 0.7 |
Postmortem& Process Improment Plan |
事后总结,并提出改进计划 | 0.5 | 0.5 |
8、小结感受:两人合作真的能够带来1+1>2的效果吗?通过这次结对合作,请谈谈你的感受和体会
两人合作是否能够带来1+1>2的效果,取决于两个人之间的沟通是否有效,是否能够朝着共同的目标去各自补充,合作完成任务。对于本次我们组的结对编程,我觉得两个人合作是能带来1+1>2的效果的。通过这次结对合作,我觉得对于一个较复杂的任务而言,一个人的能力、掌握的知识毕竟有限,两个人合作编程,能够综合各自掌握的知识,在编码的过程中,两个人轮流编程,互相监督,能够及时发现错误,少走一些不必要的弯路,并且不会的地方,两个人也能够一起讨论对策,提升了编码效率。两个人的合作,只要可以有效沟通,是可以很好地达到完成任务、共同进步的效果的。
任务四
已完成项目到github。