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等操作对同伴个人项目仓库的源码进行合作修改。
- 结对同学:康旭-201871030115
- 他的博客:https://www.cnblogs.com/labmem/
- 他的Github仓库链接:https://github.com/kangxuxu/aimer
核查表
| 注意项目 | 说明 | 
|---|---|
| 概要 | 代码功能有些瑕疵,但能完成基本测试,可读性较高, | 
| 设计规范 | 对错误处理能力较好 | 
| 代码规范 | 符合规范 | 
| 具体代码 | 结构合理,基础测试可以通过 | 
| 效能 | 代码有可优化空间 | 
| 可读性 | 可读性强 | 
| 可测试性 | 基础功能可以测试通过 | 
任务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的效果,通过两个人将工作分隔开,明显的降低了工作量,同时两个人做也降低了工作难度,除此之外合作还能发现自己的不足,学习他人的长处,
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号