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。

posted @ 2022-04-03 23:15  春柚  阅读(83)  评论(1编辑  收藏  举报