201871030137-杨钦颖 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告
201871030137-杨钦颖 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告
项目 | 内容 |
---|---|
课程班级博客链接 | 班级连接 |
这个作业要求链接 | 作业连接 |
我的课程学习目标 | 1、掌握软件项目个人开发流程。 2、掌握Github发布软件项目的操作方法。 |
这个作业在哪些方面帮助我实现学习目标 | 1、实战使用了Github项目仓库,更加熟悉了Github的使用方法。 2、基本完成了个人项目的开发,掌握了项目开发流程。 |
结对方学号-姓名 | 201871030138-杨蕊媛 |
结对方本次博客作业链接 | 结对方作业连接 |
本项目Github的仓库链接地址 | 仓库连接 |
任务1:阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念
- 已完成阅读,相关概念如下:
- 代码风格规范
- 代码风格的原则是:简明,易读,无二义性。
- 缩进:4个空格,不用Tab键是因为在不同的情况下显示的长度可能不一样。
- 行宽:限定为100字符。
- 括号:在复杂的条件表达式中,可以清晰地表示逻辑优先级。
- 断行与空白的{}行:断行在程序调试时可以清晰的表达变量的变化情况,{}来判断程序的结构。
- 分行:不要把多个变量定义在一行上。
- 命名:
- 在变量名中不要提到类型或其他语法方面的描述。
- 避免过多的描述。
- 如果信息可以从上下文中得到,那么此类信息就不必写在变量名中。
- 避免可要可不要的修饰词。
- 下划线:用来分割变量名字中的作用域标注和变量的语义。
- 大小写:
- 所有类型/类/函数名都用Pascal形式(所有单词第一个字母都大写)。
- 所有变量都用Camel形式(第一个单词全部小写,随后单词用Pascal形式)。
- 类/类型/变量:名词或组合名词。
- 函数则用动词或动宾组合词来表示。
- 注释:注释是为了解释程序做什么(What),为什么这样做(Why)以及要特别注意的地方。
- 代码设计规范
- 概念:代码设计规范不光是程序书写的格式问题,而且涉及到程序设计、模块之间的关系、设计模式等方方面面,又有不少内容与具体程序设计语言息息相关(如C,C++,JAVA,C#),但是也有通用的原则。
- 函数:原则:只做一件事,并且要做好。
- goto:函数最好有单一出口,为了达到这一目的,可以使用goto。
- 错误处理:
- 参数处理:在Debug版本中,所有的参数都要验证其正确性,在正式版本中,对从外部(用户或别的模块)传递过来的参数,要验证其正确性。
- 断言:验证正确性就要用断言。
- 如何处理C++中的类
- 类:
- 使用类来封装面向对象的概念和多态。
- 避免传递类型实体的值,应该用指针传递。换句话说,对于简单的数据类型,没有必要要用类来实现。
- 对于有显示的构造和析构的类,不要建立全局的实体,因为不知道它们在何时创建和消除。
- 仅在有必要时,才是用“类”。
- class vs.struct:如果只是数据的封装,用struct即可。
- 公共/保护/私有成员:按照这样的次序来说明类中的成员。
- 数据成员:
- 数据类型的成员用m_name说明。
- 不要使用公共的数据成员,要用inline访问函数,这样可兼顾封装和效率。
- 虚函数
- 使用虚函数来实现多态。
- 仅在很有必要时,才使用虚函数。
- 如果一个类型要实现多态,在基类中的析构函数应该是虚函数。
- 构造函数
- 不要在构造函数中做复杂的操作,简单初始化所有成员即可。
- 构造函数不应该返回错误。
- 析构函数
- 把所有的清理工作都放在析构函数中。如果有些析构函数在之前就释放了,要重置这些成员为0或NULL。
- 析构函数也不应该出错。
- new和delete
- 如果可能,实现自己的new/delete,这样可以方便地加上自己的跟踪和管理机制。自己的new/delete可以包装系统提供的new/delete。
- 检查new的返回值。new不一定都成功。
- 释放指针时不用检查NULL。
- 运算符
- 在理想情况下,我们定义的类不需要自定义操作符。确有必要时,才会自定义操作符。
- 运算符不要做标准语义之外的任何动作。
- 运算符的实现必须非常有效率,如果有复杂的操作,应定义一个单独的函数。
- 当拿不定注意时,用成员函数,不要用运算符。
- 异常
- 不要用异常作为逻辑控制来处理程序的主要流程。
- 当使用异常时,要注意在什么地方清理数据。
- 异常不能跨过DLL或进程的边界来传递消息,所以异常不是万能的。
- 类型继承
- 仅在有必要时,才使用类型继承。
- 用const标注只读的参数。
- 用const标注不改变数据的函数。
- 类:
- 代码复审:看代码是否在代码规范的框架内正确的解决了问题。代码复审的形式包括:自我复审、同伴复审、团队复审。
- 结对编程:结对编程中有两个角色:领航员和驾驶员。在个人编写的过程中,很多人喜欢根据个人喜好来规定代码规范,而且存在的bug自己难以发现,因此,在结对编程时,我们可以互换角色,在开始写代码之前,规定两个人都认可的一套代码规范,并且不间断地进行复审,以减少软件中存在的问题,修复bug,提高软件质量。
任务2:评价对结对方《实验二 软件工程个人项目》的项目成果
-
克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。
-
概要部分
-
代码能符合需求和规格说明么?
代码符合要求与规格说明
-
代码设计是否有周全的考虑?
有较为周全的考虑
-
代码可读性如何?
代码可读性强
-
代码容易维护么?
容易维护
-
-
设计规范部分
-
设计是否遵从已知的设计模式或项目中常用的模式?
遵从
-
有没有硬编码或字符串/数字等存在?
没有
-
代码有没有依赖于某一平台,是否会影响将来的移植(如Win32到Win64)?
不会影响移植
-
在本项目中是否存在类似的功能可以调用而不用全部重新实现?
没有
-
有没有无用的代码可以清除?
没有
-
-
代码规范部分
-
修改的部分符合代码标准和风格么(详细条文略)?
符合
-
-
具体代码部分
-
有没有可能导致资源泄露(内存、文件、各种GUI资源、数据库访问的连接,等等)?有没有可能优化?
不会导致资源泄露;还有优化的可能性
-
数据结构中是否有无用的元素?
没有
-
-
效能
-
代码的效能(Performance)如何?最坏的情况是怎样的?
达到了部分任务要求
-
代码中,特别是循环中是否有明显可优化的部分?
没有
-
-
可测试性
-
代码是否需要更新或创建新的单元测试?
可以继续开发
-
-
-
依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。
任务3:采用两人结对编程方式,设计开发一款D{0-1}KP 实例数据集算法实验平台,使之具有以下功能
功能设计
- 平台基础功能:实验二 任务3;
- D{0-1}KP 实例数据集需存储在数据库;
- 平台可动态嵌入任何一个有效的D{0-1}KP 实例求解算法,并保存算法实验日志数据;
- 人机交互界面要求为GUI界面(WEB页面、APP页面都可);
- 查阅资料,设计遗传算法求解D{0-1}KP,并利用此算法测试要求(3);
设计实现
- 在实验二的基础上添加GUI界面
- 学习并添加遗传算法
测试运行
-
选择需要读取的文件
-
选择需要读取第几组数据
-
散点图
-
遗传算法运行结果图
-
数据库中导入结果
-
有效数据的展示,其中包含选定数据的价值重量、第三项价值:重量比的排序、利用动态规划算法、遗传算法求解指定D{0-1} KP数据的最优解和求解时间(以秒为单位)
-
在.txt文件中存储的运行结果
代码展示
-
导入数据库
# 创建数据库 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
总结
PSP展示
PSP2.1 | 任务内容 | 计划共完成需要的时间(min) | 实际完成需要的时间(min) |
---|---|---|---|
Planning | 计划 | 20 | 20 |
Estimate | 估计这个任务需要多少时间,并规划大致工作步骤 | 20 | 20 |
Development | 开发 | 1090 | 1200 |
Analysis | 需求分析 (包括学习新技术) | 120 | 155 |
Design Spec | 生成设计文档 | 30 | 20 |
Design Review | 设计复审 (和同事审核设计文档) | 20 | 20 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 35 |
Design | 具体设计 | 60 | 50 |
Coding | 具体编码 | 600 | 650 |
Code Review | 代码复审 | 30 | 30 |
Test | 测试(自我测试,修改代码,提交修改) | 200 | 240 |
Reporting | 报告 | 100 | 100 |
Test Report | 测试报告 | 30 | 40 |
Size Measurement | 计算工作量 | 40 | 30 |
Postmortem & Process Improvement Plan | 事后总结 ,并提出过程改进计划 | 30 | 30 |
commit记录
GitHub项目仓库连接
任务4:完成个人项目报告博文作业
- 已完成博客
写在后面
本次实验项目在实验二的基础上新添加了数据库的导入、GUI界面以及遗传算法等要求。为实现这些功能我们一起学习了如何在python中添加数据库和GUI界面,这些知识虽然之前学过但都只是皮毛,通过本次实验强化了我对相关知识的理解与运用。除此之外对我们来说最难的就是怎样使用遗传算法实现D{0-1}KP 背包问题,经过查阅学习资料与编码测试我们发现:使用遗传算法进行测试,最后产生的结果不一定是问题的最优解,甚至会出现结果不一致。最后通过查阅相关资料证实了我们的发现是符合遗传算法的。
在本次实验中我与我的结对对象是舍友,这大大方便了我们的沟通与交流,但这也使我们没有保留交流、编程时的结对图片。但在结对合作中我体会到了“1+1>2”的效果。每个人都题出自己的理解与想法,同时又会碰撞出更多更好的编程思路,提高了项目完成效率。
不足之处:未设置滚动条,当数据较多时无法看到后面的数据