201871030124-王超怀 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

项目 内容
课程班级博客 https://edu.cnblogs.com/campus/xbsf/2018CST
这个作业要求链接 https://www.cnblogs.com/nwnu-daizh/p/14604444.html
我的课程学习目标 1.双人合作完成项目 2.通过github作对同伴个人项目仓库的源码 3.学习遗传算法
这个作业在哪些方面帮助我实现学习目标 1.我了解了遗传算法 2.通过这次实验我对双人合作编程重要性有了认识
结对方学号-姓名 康旭-201871030115
结对方本次博客作业链接 https://www.cnblogs.com/labmem/p/14656486.html
项目GitHub仓库地址 https://github.com/OwOWang/O

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

代码规范
  • 原则一:代码应该简洁易懂,逻辑清晰

    • 因为软件是需要人来维护的。这个人在未来很可能不是你。所以首先是为人编写程序,其次才是计算机:
      • 不要过分追求技巧,降低程序的可读性。
      • 简洁的代码可以让bug无处藏身。要写出明显没有bug的代码,而不是没有明显bug的代码。
  • 原则二:面向变化编程,而不是面向需求编程

    • 需求是暂时的,只有变化才是永恒的。

      本次迭代不能仅仅为了当前的需求,写出扩展性强,易修改的程序才是负责任的做法,对自己负责,对公司负责。

  • 原则三:先保证程序的正确性,防止过度工程

    • 过度工程(over-engineering):在正确可用的代码写出之前就过度地考虑扩展,重用的问题,使得工程过度复杂
代码设计规范
  • 牵扯到程序设计、模块之间的关系、设计模式等方方面面的通用原则。

    包括:函数、goto、错误处理。

代码复审
  • 代码复审的正确定义就是:看代码是否在代码规范的框架里正确的解决了问题。
  • 代码复审分为自我复审,同伴复审,团队复审,其目的在于找出代码的错误,发现逻辑的错误,发现算法的错误,发现潜在的错误和回归性错误,教育开发人员,传授经验,让更多的成员熟悉项目各部分的代码,同时熟悉和应用领域相关的实际知识。
  • 在代码复审后,一定要注意,把所有的错误记在一个“我常犯的错误”表中,作为以后自我复审的第一步,团队也应该注意用项目管理软件来记录问题,以便日后查询。
  • 代码复审应该查哪些东西呢,1.概要部分 2.设计规范部分 3.代码规范部分 4.具体代码部分 5.效能 6.可读性 7.可测试性。
结对编程
  • 程序员之间的合作会经历萌芽、磨合、规范、创造、解体阶段。
  • 要想说服别人,就要注意说话的语气和方式,少用断言,多给别人解释的机会,少直接说服别人,而是用感情分析来吸引别人,总体思想即--不是把对方推开,而是拉近对方,吸引对方加入,建立共识。举个例子,用“能不能再说说你的理由”代替“就是这样的,听我的没错”。
  • 结对编程中不好的习惯是:不拘小节、喜欢发号施令、深藏不露、跳跃很大的人。

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

(1)对项目博文作业进行阅读并进行评论,评论要点包括:博文结构、博文内容、博文结构与PSP中“任务内容”列的关系、PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究,将以上评论内容发布到博客评论区。
(2)克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。
(3)依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。
核查表
注意项目 说明
概要 代码功能有些瑕疵,但能完成基本测试,可读性较高,
设计规范 对错误处理能力较好
代码规范 符合规范
具体代码 结构合理,基础测试可以通过
效能 代码有可优化空间
可读性 可读性强
可测试性 基础功能可以测试通过

任务3:采用两人结对编程方式,设计开发一款D{0-1}KP 实例数据集算法实验平台,使之具有以下功能:

(1)平台基础功能:实验二 任务3;
(2)D{0-1}KP 实例数据集需存储在数据库;
(3)平台可动态嵌入任何一个有效的D{0-1}KP 实例求解算法,并保存算法实验日志数据;
(4)人机交互界面要求为GUI界面(WEB页面、APP页面都可);
(5)查阅资料,设计遗传算法求解D{0-1}KP,并利用此算法测试要求(3);
(6)附加功能:除(1)-(5)外的任意有效平台功能实现。
PSP流程
任务内容 计划共完成需要的时间(min) 实际完成需要的时间(min)
计划 70 40
查阅相关资料 30 20
规划PSP流程 40 20
开发 480 300
编写算法 180 120
具体设计 120 200
代码复审 180 180
报告 130 110
编写博客 90 90
上传代码 10 10
总结流程 30 20
1.需求分析
  • 可正确读入实验数据文件的有效D{0-1}KP数据;
  • 能够绘制任意一组D{0-1}KP数据以重量为横轴、价值为纵轴的数据散点图;
  • 能够对一组D{0-1}KP数据按项集第三项的价值:重量比进行非递增排序;
  • 用户能够自主选择动态规划算法、回溯算法求解指定D{0-1} KP数据的最优解和求解时间(以秒为单位);
  • 任意一组D{0-1} KP数据的最优解、求解时间和解向量可保存为txt文件或导出EXCEL文件
2.功能设计
  • 读入文件

    public static void main(String[] args) {
    		File data = new File(".//data//data1.txt");
    		//背包容量
    		//种群规模
    		//最大代数
    		//交叉率(所有的个体都需要相互交叉的,这里的交叉率指交叉时每位交叉发生交叉的可能性)
    		//变异率(某个个体发生变异的可能性)
    		//对于确定发生变异的个体每位发生变异的可能性
    		//物品重量和物品价值的数据文件
    		GAKnapsack gaKnapsack = new GAKnapsack(1000, 200, 2000, 0.5f, 0.05f, 0.1f, data);
    		gaKnapsack.solve();
    
  • 绘制数据散点图

    protected void paintComponent(Graphics g) {
    	 super.paintComponent(g);
    	  Graphics2D g2 = (Graphics2D)g;
    	  g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    	  RenderingHints.VALUE_ANTIALIAS_ON);
    	 int w = getWidth();
    	 int h = getHeight();
    	 g2.draw(new Line2D.Double(PAD, PAD, PAD, h-PAD));
    	 g2.draw(new Line2D.Double(PAD, h-PAD, w-PAD, h-PAD));
    	 double xInc = (double)(w - 2*PAD)/(data.length-1);
    	 double scale = (double)(h - 2*PAD)/getMax();
    	 g2.setPaint(Color.red);
    	 for(int i = 0; i < data.length; i++) {
    	 double x = PAD + i*xInc;
    	 double y = h - PAD - scale*data[i];
    	 g2.fill(new Ellipse2D.Double(x-2, y-2, 4, 4));
    }
      
    
3.功能实现
4.核心代码展示
/ 计算种群中各个个体的累积概率,前提是已经计算出各个个体的适应度fitness[max],作为赌轮选择策略一部分,Pi[max]
	void countRate() {
		int k;
		double sumFitness = 0;// 适应度总和
 
		int[] tempf = new int[scale];
 
		for (k = 0; k < scale; k++) {
			tempf[k] = fitness[k];
			sumFitness += tempf[k];
		}
 
		Pi[0] = (float) (tempf[0] / sumFitness);
		for (k = 1; k < scale; k++) {
			Pi[k] = (float) (tempf[k] / sumFitness + Pi[k - 1]);
		}
	}
 
	// 挑选某代种群中适应度最高的个体,直接复制到子代中
	// 前提是已经计算出各个个体的适应度Fitness[max]
	public void selectBestGh() {
		int k, i, maxid;
		int maxevaluation;
 
		maxid = 0;
		maxevaluation = fitness[0];
		for (k = 1; k < scale; k++) {
			if (maxevaluation < fitness[k]) {
				maxevaluation = fitness[k];
				maxid = k;
			}
		}
 
		if (bestLength < maxevaluation) {
			bestLength = maxevaluation;
			bestT = t;// 最好的染色体出现的代数;
			for (i = 0; i < LL; i++) {
				bestTour[i] = oldPopulation[maxid][i];
			}
		}
 
		// 复制染色体,k表示新染色体在种群中的位置,kk表示旧的染色体在种群中的位置
		copyGh(0, maxid);// 将当代种群中适应度最高的染色体k复制到新种群中,排在第一位0
	}
 
	// 复制染色体,k表示新染色体在种群中的位置,kk表示旧的染色体在种群中的位置
	public void copyGh(int k, int kk) {
		int i;
		for (i = 0; i < LL; i++) {
			newPopulation[k][i] = oldPopulation[kk][i];
		}
	}
 
	// 赌轮选择策略挑选
	public void select() {
		int k, i, selectId;
		float ran1;
		for (k = 1; k < scale; k++) {
			ran1 = (float) (random.nextInt(65535) % 1000 / 1000.0);
			// System.out.println("概率"+ran1);
			// 产生方式
			for (i = 0; i < scale; i++) {
				if (ran1 <= Pi[i]) {
					break;
				}
			}
			selectId = i;
			copyGh(k, selectId);
		}
	}
 
	public void evolution() {
		int k;
		// 挑选某代种群中适应度最高的个体
		selectBestGh();
		// 赌轮选择策略挑选scale-1个下一代个体
		select();
		float r;
 
		// 交叉方法
		for (k = 0; k < scale; k = k + 2) {
			r = random.nextFloat();// /产生概率
			// System.out.println("交叉率..." + r);
			if (r < Pc) {
				// System.out.println(k + "与" + k + 1 + "进行交叉...");
				OXCross(k, k + 1);// 进行交叉
			} else {
				r = random.nextFloat();// /产生概率
				// System.out.println("变异率1..." + r);
				// 变异
				if (r < Pm) {
					// System.out.println(k + "变异...");
					OnCVariation(k);
				}
				r = random.nextFloat();// /产生概率
				// System.out.println("变异率2..." + r);
				// 变异
				if (r < Pm) {
					// System.out.println(k + 1 + "变异...");
					OnCVariation(k + 1);
				}
			}
 
		}
 
	}
	
 
	// 两点交叉算子
	void OXCross(int k1, int k2) {
		int i, j, flag;
		int ran1, ran2, temp = 0;
 
		ran1 = random.nextInt(65535) % LL;
		ran2 = random.nextInt(65535) % LL;
 
		while (ran1 == ran2) {
			ran2 = random.nextInt(65535) % LL;
		}
		if (ran1 > ran2)// 确保ran1<ran2
		{
			temp = ran1;
			ran1 = ran2;
			ran2 = temp;
		}
		flag = ran2 - ran1 + 1;// 个数
		for (i = 0, j = ran1; i < flag; i++, j++) {
			temp = newPopulation[k1][j];
			newPopulation[k1][j] = newPopulation[k2][j];
			newPopulation[k2][j] = temp;
		}
 
	}
 
	// 多次对换变异算子
	public void OnCVariation(int k) {
		int ran1, ran2, temp;
		int count;// 对换次数
		count = random.nextInt(65535) % LL;
 
		for (int i = 0; i < count; i++) {
 
			ran1 = random.nextInt(65535) % LL;
			ran2 = random.nextInt(65535) % LL;
			while (ran1 == ran2) {
				ran2 = random.nextInt(65535) % LL;
			}
			temp = newPopulation[k][ran1];
			newPopulation[k][ran1] = newPopulation[k][ran2];
			newPopulation[k][ran2] = temp;
		}
	}

8.小结感受:两人合作真的能够带来1+1>2的效果吗?通过这次结对合作,请谈谈你的感受和体会。

通过这次结对编程我发现两人合作确实能带来1+1>2的效果,通过两个人将工作分隔开,明显的降低了工作量,同时两个人做也降低了工作难度,除此之外合作还能发现自己的不足,学习他人的长处,

posted @ 2021-04-14 10:31  OwO柯戈喵  阅读(71)  评论(1编辑  收藏  举报