201971010125-李涛 实验三 结对项目—《{0-1}KP 实例数据集算法实验平台》项目报告

项目
内容
课程班级博客
2019级卓越工程师班
作业要求
实验三
我的课程学习目标 (1)体验软件项目开发中的两人合作,练习结对编程(Pair programming)。
(2)掌握Github协作开发软件的操作方法。
作业对我实现目标的帮助 (1)学习软件项目的开发过程,熟悉软件开发项目的流程 。
(2)学会运用项目Github发布项目的操作过程,熟练使用学习辅助工具。
(3)构建之法的阅读加深对软件工程的学习。
结对对方信息
201971010117 刘春丽
结对方本次博客链接
结对方作业链接
本项目Github的仓库链接地址
项目Github的仓库地址

实验内容

任务一:阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念;

1、 构建之法第三章(软件工程师的成长)

  • 个人能力的衡量和发展,软件开发流程不光指团队的流程,还包括个人的开发流程。个人要做到:
    • 能有效和其他队员交流;
    • 按时交付,说到做到;
    • 接受团队赋予的角色并按角色要求工作;
    • 全力投入团队的活动,按照团队流程的要求进行工作。
  • 软件工程师的思维误区
    • 常见的有不分主次,想解决所有依赖的问题;
    • 过早优化:工程师抓住局部问题,花大量的时间优化,无视全局;
    • 过早扩大化/泛化:典型的“画扇面”,没有了解到必要性,难度和时机。

2、 构建之法第四章(两人合作)

  • 代码风格规范:主要是文字上的规定,看似表面文章,实际上非常重要。
    • 原则:简明,易读,无二义性。
    • 主要内容:缩进(四个空格),行宽,括号,断行与空白的{}行,分行,命名,下划线,大小写,注释。
  • 代码设计规范:牵涉到程序设计,模块之间的关系设计模式等方方面面的通用原则。
    • 主要内容:函数,goto(实现函数的单一出口),错误处理(参数处理,断言),如何处理C++中的类。
  • 代码复审:看代码是否在代码规范的框架内正确的解决了问题。
    • 主要形式:自我复审,同伴复审,团队复审。最基本的复审手段就是同伴复审。
  • 结对编程:一对程序员肩并肩,平等地,互补地进行开发工作。

任务二:两两自由结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价

项目
内容
结对对方信息
201971010117 刘春丽
结对方实验二博客链接 201971010117- 刘春丽 实验二 个人项目 《0/1背包问题》项目报告
结对方实验二Github的仓库链接地址
项目Github的仓库地址

1、博文评价

  • 博文结构:
    博文整体结构完整,排列整齐,值得学习。在文字段落较多的地方采用图文搭配会更加清晰,可以尝试使用流程图让内容简洁清晰。
  • 博文内容:
    完整的表述了实验要求的内容,围绕老师给出的任务行文流畅;如果需求分析和功能设计可以使用更加简单的形式来表达一下,比如采用流程图会让表达的内容简单明了。
  • 博文结构与PSP中“任务内容”列的关系:
    博文结构与“内容任务”大体一致。“内容任务”从整体计划到最后的总结,基本阐述了整个项目完成的过程。
  • PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究:
    实际完成需要的总时间和计划共完成需要的总时间相差不多,但是总体的时间对比中会发现计划和文档撰写上花费是时间比计划完成的时间少;代码编写和总体设计上花费是时间比计划中花费的多,可以看出博主擅长项目的整体把控和文字总结,但在实际的代码编写和项目设计上还需要继续努力哦。
  • 已完成将以上评论内容发布到对方博客评论区。

2、克隆结对方实验项目

  • 克隆结对方实验二项目:

  • 测试运行代码:

  • 检查表复审:

核查表
执行情况
概要部分
代码符合需求和规格说明么? 代码基本符合需求和规格说明
代码设计是否考虑周全? 代码设计有周全的考虑
代码可读性如何? 代码可读性还不错
代码容易维护么? 代码容易维护
代码的每一行都执行并检查过了吗? 代码的每一行都执行并检查过了
设计规范部分
设计是否遵从已知的设计模式或项目中常用的模式? 代码遵从已知的设计模式或项目中常用的模式
代码有没有依赖于某一平台,是否会影响将来的移植(如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:最初的开发者同意你的修改,将其合并到自己的项目中。

  • 日志数据,Commits数据,帮助结对方完善了界面代码

任务三:采用两人结对编程方式,设计开发一款{0-1}KP 实例数据集算法实验平台

1、项目背景

  • {0-1}背包问题({0-1 }Knapsack Problem,{0-1}KP)是最基本的KP问题形式,它的一般描述为:从若干具有价值系数与重量系数的物品(或项)中,选择若干个装入一个具有载重限制的背包,如何选择才能使装入物品的重量系数之和在不超过背包载重前提下价值系数之和达到最大?

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、测试运行

  • 程序运行
    • 选择要读取的文件:

    • 选择要文件中要读取哪一组数据:

    • 读取到的数据存入数据库:

    • 散点图的显示:

    • 遗传算法运行结果(需要注意的是:遗传算法是一种近似最优化算法,它的每个解都是近似最优解,不能保证是全局最优。):

7、描述结对的过程,提供两人在讨论、细化和编程时的结对照片

因为都在一个宿舍,所以聚集在一起来共同完成这个项目是比较方便的,并且比较熟悉,在沟通方面也是顺畅的。最开始是一起分析确定了项目要实现哪一些功能,GUI界面如何呈现,各类功能如何嵌入GUI界面,选择什么语言来编程,大概的方向确定好之后,就开始着手写代码。在编程的过程中,两个人轮流编程,一人编程的时候,另一人帮忙查资料,检查代码中是否有错误,提醒修改,遇到麻烦的地方,两个人一起思考、商量解决办法。

  • 有效数据的展示,其中包含选定数据的价值重量、第三项价值:重量比的排序、利用动态规划算法、遗传算法求解指定D{0-1} KP数据的最优解和求解时间(以秒为单位):

  • 此次作业的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的效果的。通过这次结对合作,我觉得对于一个较复杂的任务而言,一个人的能力、掌握的知识毕竟有限,两个人合作编程,能够综合各自掌握的知识,在编码的过程中,两个人轮流编程,互相监督,能够及时发现错误,少走一些不必要的弯路,并且不会的地方,两个人也能够一起讨论对策,提升了编码效率。两个人的合作,只要可以有效沟通,是可以很好地达到完成任务、共同进步的效果的。

任务四 完成结对项目报告博文作业

posted @ 2022-04-03 23:11  李涛。  阅读(87)  评论(2编辑  收藏  举报