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的效果,通过两个人将工作分隔开,明显的降低了工作量,同时两个人做也降低了工作难度,除此之外合作还能发现自己的不足,学习他人的长处,