201971010247-谢宇涵 实验三 结对项目—《{0-1}KP 实例数据集算法实验平台》项目报告
项目 | 内容 |
课程班级博客链接 | 详细内容请点击查看 |
作业要求链接 | 详细内容请点击查看 |
我的课程学习目标 | (1)体验软件项目开发中的两人合作,练习结对编程 (2)掌握Github协作开发软件的操作方法 |
这个作业在哪些方面帮助我实现学习目标 | (1)自学《构建之法》第3-4章内容,学习本次作业相关概念 (2)结对编程,评价对方《实验二 软件工程个人项目》并学习对方优点 (3)合作开发设计D{0-1}KP 实例数据集算法实验平台 (4)查阅资料设计遗传算法解决D{0-1}KP |
结对方学号-姓名 | 201971010253-张萌 |
结对方本次博客作业链接 | 对方博文链接 |
本项目Github的仓库链接地址 | 仓库链接 |
一、阅读《现代软件工程—构建之法》第3-4章内容
1. 代码风格规范:主要是文字上的规定。代码风格的原则是:简明、易读、无二义性,包括对于缩进、行宽、括号、分行、命名、下划线、注释、大小写以及断行与空白的{}行的处理,具体如下:
- 缩进:可以使用Tab键以及2、4、8等空格。个人认为依据不同是编程语言,可以使用不同的缩进方式。
- 行宽:对行宽进行同一设置。
- 括号:用括号清楚的表明逻辑优先级。
- 断行与空白的{}行:主要是在多层循环中规范使用。
- 分行:不要把多条语句放在一行上。
- 命名:命名能够表明变量的类型及相应的语义,简洁易懂。
- 下换线:合理使用来分隔变量名字中的作用域标注和变量的语义。
- 大小写:多个单次组成的变量名,用大小写区分,例如著名的驼峰式命名法。
- 注释:能够很好的解释程序是做什么的,以及为什么这样做。
2. 代码设计规范:不光是程序书写格式的问题,而且牵涉到程序设计、模块之间的关系、设计模式等的方方面面,主要有以下几个部分:
- goto:函数最好有单一的出口,可以使用goto。
- 函数:能够很好的完成一件事。
- c++类的处理:注意类、classvc.struct、公共/保护/私有成员、数据成员、虚函数、构造函数、析构函数、new和delete、运算符、异常处理、类型继承等的规范设计。
- 错误处理:预留足够的时间,使用的方法包括参数处理和断言。
- 断言:使用断言来验证正确性。
- 参数处理:在debug版本中,所有的参数都要验证其正确性。在正式版本中,对从外部(用户或别的模块)传递过来的参数,要验证其正确性。
- 数据成员:数据类型的成员用m_ name说明。不要使用公共的数据成员,要用inline访问函数,这样可兼顾封装和效率。
- 构造函数:不要在构造函数中做复杂的操作,简单初始化所有数据成员即可。构造函数不应该返回错误(事实上也无法返回)。把可能出错的操作放到HrInit()或FInit()中。
- 异常:异常是在“异乎寻常”的情况下出现的,它的设置和处理都要花费“异乎寻常”的开销,所以不要用异常作为逻辑控制来处理程序的主要流程。了解异常及处理异常的花销,在C++语言中,这是不可忽视的开销。当使用异常时,要注意在什么地方清理数据。异常不能跨过DLL或进程的边界来传递信息,所以异常不是万能的。
- 运算符:在理想状态下,我们定义的类不需要自定义操作符。确有必要时,才会自定义操作符。运算符不要做标准语义之外的任何动作。运算符的实现必须非常有效率,如果有复杂的操作,应定义一个单独的函数。当你拿不定主意的时候,用成员函数,不要用运算符。
3. 代码复审:看代码是否在代码规范的框架内正确地解决了问题。代码复审的三种形式:自我复审、同伴复审、团队复审。
- 自我复审:用同伴复审的标准来要求自己。不一定最有效, 因为开发者对自己总是过于自信。如果能持之以恒,则对个人有很大好处。
- 同伴复审:简单易行。
- 团队复审:有比较严格的规定和流程,适用于关键的代码,以及复审后不再更新的代码。覆盖率高——有很多双眼睛盯着程序,但效率可能不高。
4. 结对编程:指一起分析,一起设计,一起写测试用例,一起做单元测试,一起做集成测试,一起写文档等等。
- 角色:驾驶员:控制键盘输入;领航员:起到领航、提醒的作用。
- 好处:在开发层次,可以提供更好的设计质量和代码质量,两人合作解决问题的能力更强;对开发人员,带来更多的信心,高质量的产出带来更高的满足感;企业管理层次上,有效地交流,相互学习和传递经验,分享知识,取得更高的投入产出比。
- 目的:每人在各自独立设计、实现软件的过程中不免要犯这样那样的错误。在结对编程中,因为有随时的复审和交流,程序各方面的质量取决于一对程序员中各方面水平较高的那一位。这样,程序中的错误就会少得多,程序的初始质量会高很多,这样会省下很多以后修改、测试的时间。
二、对结对方《实验二 软件工程个人项目》的项目成果进行评价
项目成果评价 | 内容 |
结队方 | 201971010253-张萌 |
结对方实验二博客作业链接 | 对方博文链接 |
结对方实验二的Github的仓库链接地址 | 仓库链接 |
(1)项目博文评价:
1. 博文结构:
博文整体排版较好,清晰易读,但是在表格的设计部分应该提升一下。
2. 博文内容:
实验内容完成度不错,对需求分析、功能设计及设计实现设计实现都进行了详细的称述,但是没有完成扩展部分。
3. 博文结构与PSP中“任务内容”列的关系:
博文按照PSP的各个流程进行撰写,使得项目的完成更加系统化,这一点完成度很好。
4. PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究:
在计划以及需求分析等前期工作环节中,预计花费时间比实际花费时间少,但后期代码编写环节花费时间较多,可能是编码能力有待提升,也有可能是前期准备工作可以做得更加细致。
(2)克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。
- 克隆结对方项目源码
- 测试运行代码
- 核查表复审
核查表 | 执行情况 |
---|---|
概要部分 | |
代码符合需求和规格说明么? | 代码符合需求 |
代码设计是否考虑周全? | 考虑周全 |
代码可读性如何? | 可以顺利阅读 |
代码容易维护么? | 不容易维护 |
代码的每一行都执行并检查过了吗? | 是的,可执行。 |
设计规范部分 | |
设计是否遵从已知的设计模式或项目中常用的模式? | 遵从。 |
代码有没有依赖于某一平台,是否会影响将来的移植(如Win32到Win64)? | 没有,不会影响移植,任何平台都可以。 |
开发者新写的代码能否用已有的Library/SDK/Framework中的功能实现?在本项目中是否存在类似的功能可以调用而不用全部重新实现? | 可以用;存在,有些代码是可以调用的 |
有没有无用的代码可以清除?(很多人想保留尽可能多的代码,因为以后可能会用上,这样导致程序文件中有很多注释掉的代码,这些代码都可以删除,因为源代码控制已经保存了原来的老代码) | 有。 |
代码规范部分 | |
修改的部分符合代码标准和风格么? | 修改的部分不符合代码标准和风格。 |
具体代码部分 | |
有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常? | 对错误都进行了处理,没有异常。 |
参数传递有无错误,字符串的长度是字节的长度还是字符(可能是单/双字节)的长度,是以0开始计数还是以1开始计数? | 无错误;本项目中是以0开始计数。 |
边界条件是如何处理的?switch语句的default分支是如何处理的?循环有没有可能出现死循环? | switch语句的default分支返回false,没有出现死循环。 |
有没有使用断言(Assert)来保证我们认为不变的条件真的得到满足? | 无。 |
对资源的利用是在哪里申请,在哪里释放的?有没有可能导致资源泄露(内存、文件、各种GUI资源、数据库访问的连接,等等)?有没有优化的空间? | 都在内存中完成,很有可能泄露 |
数据结构中有没有用不到的元素? | 无,整体比较简洁 |
效能 | |
代码的效能(Performance)如何?最坏的情况如何? | 达到了具体任务的要求。 |
代码中,特别是循环中是否有明显可优化的部分(C++中反复创建类,C#中 string 的操作是否能用StringBuilder 来优化)? | 有 |
对于系统和网络调用是否会超时?如何处理? | 没有出现超时现象 |
可读性 | |
代码可读性如何?有没有足够的注释? | 可以顺利读取;代码有足够的注释 |
可测试性 | |
代码是否需要更新或创建新的单元测试?针对特定领域的开发(如数据库、网页、多线程等),可以整理专门的核查表。 | 可以继续开发,增加更多的功能 |
(3)依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。
三、项目开发背景
采用两人结对编程方式,设计开发一款{0-1}KP 实例数据集算法实验平台,使之具有以下功能::
1.平台基础功能:实验二 任务3;
2.{0-1}KP 实例数据集需存储在数据库;
3.平台可动态嵌入任何一个有效的{0-1}KP 实例求解算法,并保存算法实验日志数据;
4.人机交互界面要求为GUI界面(WEB页面、APP页面都可);
5.查阅资料,设计遗传算法求解{0-1}KP,并利用此算法测试要求(3);
6.附加功能:除(1)-(5)外的任意有效平台功能实现。
四、项目实施过程
1.需求分析
2.软件设计说明
(1)在实验二-个人项目的基础上进行开发;
(2)人机交互界面通过python来编写GUI界面;
(3)将D{0-1}KP实例数据集存储在数据库,在GUI界面可进行数据的查询;
(4)输入需要绘制散点图或者需要排序的数据集以及数据项后进行散点图的绘制或者数据的排序;
(5)平台动态嵌入有效的D{0-1}KP实例求解算法,并且可以保存算法实验日志数据;
(6)添加遗传算法。在原来个人项目的基础上添加遗传算法,在GUI界面上添加遗传算法的选择按钮。
遗传算法(Genetic Algorithm,GA)最早是由美国的 John holland于20世纪70年代提出,该算法是根据大自然中生物体进化规律而设计提出的。是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。该算法通过数学的方式,利用计算机仿真运算,将问题的求解过程转换成类似生物进化中的染色体基因的交叉、变异等过程。在求解较为复杂的组合优化问题时,相对一些常规的优化算法,通常能够较快地获得较好的优化结果。遗传算法已被人们广泛地应用于组合优化、机器学习、信号处理、自适应控制和人工生命等领域。
- 遗传算法的概述图:
3.软件实现
4.程序运行
(1)将{0-1}KP 实例数据集需存储在数据库中(以beibao0.in为例)
(2)人机交互界面通过python来编写GUI界面
- 一级界面
- 二级界面
- 三级界面
(3)绘制散点图(以beibao0.in为例)
(4)数据的排序(以beibao0.in为例)
(5)利用遗传算法进行求解
(6)拓展功能:绘制任意一组以价值/重量为纵轴的折线图(以beibao0.in为例)
5.核心代码展示
- find函数:利用数据库进行数据查询
def find(result=[]):
win1 = tkinter.Toplevel()
win1.title('查询数据')
win1.geometry('500x300')
sw = win1.winfo_screenwidth()
sh = win1.winfo_screenheight()
win1.geometry('+%d+%d' % ((sw - 500) / 2, (sh - 300) / 2))
tkinter.messagebox.showinfo("结果如下", result)
win1.destroy()
- CreateDataBase函数:导入数据库
def CreateDataBase(self):
global i
global d
global cubage
global profit
global weight
global pw
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()
conn.close()
return result
- 遗传算法求解
##初始化,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.结对的过程
7.此次结对作业的PSP
PSP2.1 | 任务内容 | 计划完成共需要的时间(min) | 实际完成共需要的时间(min) |
Planning | 计划 | 20 | 20 |
Estimate | 估计这个任务需要多少时间,并规划大致工作步骤 | 20 | 20 |
Development | 开发 | 460 | 515 |
Analysis | 需求分析(包括学习新技术) | 15 | 20 |
Design Spec | 生成设计文档 | 12 | 20 |
Design Review | 设计复审(和同事审核设计文档) | 25 | 40 |
Coding Standard | 代码规范(为目前的开发制定合适的规范) | 10 | 16 |
Design | 具体设计 | 20 | 25 |
Coding | 具体编码 | 270 | 240 |
Code Review | 代码复审 | 15 | 30 |
Test | 测试(自我测试,修改代码,提交修改) | 20 | 10 |
Reporting | 报告 | 40 | 50 |
Test Reporting | 测试报告 | 10 | 15 |
Size Measurement | 计算工作量 | 10 | 8 |
Postmortem & Process Improvenment Plan | 事后总结,并提出过程改进计划 | 20 | 27 |
7.小结感受
本次实验项目在实验二的基础上新添加了数据库的导入、GUI界面以及遗传算法等要求。我们一起学习了如何在python中添加数据库和GUI界面,两个人合作完成项目总体来说效率会高很多,因为可以根据各自擅长的板块来划分任务,各司其职,能快速完整的完成任务,同时也能向对方学习。但是合作完成任务也存在不足就是在遇到思想分歧的时候,每个人都想用自己的方法来设计项目,好在经过了沟通,最终达成一致,顺利地完成了任务。