高级软件工程第二次作业

项目简介

  • 项目地址: https://github.com/gpyu/sudoku

  • 操作系统:Window 10 64bit

  • 开发工具:Visual Studio 2017

  • 版本控制:Git

  • 流程图:Visio 2013

  • 文档编辑器:MarkDownPad2

PSP

PSP2.1 Personal Software Process Stages 预估耗时(分钟)
Planning 计划
· Estimate · 估计这个任务需要多少时间 30
Development 开发
· Analysis · 需求分析 (包括学习新技术) 180
· Design Spec · 生成设计文档 60
· Design Review · 设计复审 (和同事审核设计文档) 30
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20
· Design · 具体设计 120
· Coding · 具体编码 150
· Code Review · 代码复审 60
· Test · 测试(自我测试,修改代码,提交修改) 60
Reporting 报告
· Test Report · 测试报告 30
· Size Measurement · 计算工作量 30
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 60
合计 830

解题思路

刚看到这题的时候,感觉被难住了,平时并没有做过数独,一开始只想着先把每个粗线宫填写满,然后再填写第二个粗线宫,并判断每一行每一列是否符合要求,以此类推,但最后觉得这样子似乎不可行,行列的判断似乎变得很麻烦,最后我还是决定上网查找数独相关的解题思路,最后采取以下方案,思路如下:

  1. 先将1~9个数随机排序作为9*9罗盘的第一行数据
  2. 同1,也生成一个1~9的随机序列记为T(t1,t2,t3,t4,t5,t6,t7.t8,t9),作为接下来填表的数据
  3. 由于第一行记录已随机生成,因此我们从第二行还是填写表格,每次遍历T中的每个记录,判断是否符合数独的要求(即:每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复),如果符合要求即填写进入数独表,直到当前行填写完毕。
  4. 接下来第三行至第九行重复过程3,直到填充完整个数独表格

设计实现

代码结构如下:

/ main.cpp
	/ main()  #主程序入库,功能:校验用户输入、调用gennerator中的generateSudoku方法、运行结果的输出
/ generator.cpp
	/ generateSudoku() #生成数独表
	/ init()  #初始化数独表行,即对1~9进行随机排序
	/ checkIsLegal()  #判断填写的数独是否符合行、列、粗线宫不重复的规则
	/ fillBlank()  #使用递归对每一个空白格进行填写

fillBank函数流程图:

代码说明

//初始化数独的第一样(1~9重新随机排序)
void init(int *list) {
	//第一行初始赋值
	for (int i = 0; i < 9; i++) {
		list[i] = i+1;
	}
	//获取时间,根据时间生随机排序
	unsigned seed = chrono::system_clock::now().time_since_epoch().count();
	shuffle(list, list + 9, default_random_engine(seed));
}


//检查填入的数字是否符合要求
bool checkIsLegal(int i, int j, int num) {
	//判断行相同
	for (int k = 0; k < j; k++) {
		if (scene[i][k] == num) {
			return false;
		}
	}
		
	//判断列相同
	for (int k = 0; k < i; k++) {
		if (scene[k][j] == num) {
			return false;
		}
	}
		
	//判断区域相同
	int count = j % 3 + i % 3 * 3;
	while (count--) {
		if (!(scene[i - i % 3 + count / 3][j - j % 3 + count % 3] - num)) {
			return false;
		}	
	}
	return true;
}

//填充表格
bool fillBlank(int y, int x, int *numloc) {
	//当前所有行都填写完成后结束
	if (y > 8) {
		return true;
	}
	//判断填写数字是否符合要求,符合填写数字
	if (checkIsLegal(y, x, *numloc)){
		scene[y][x] = *numloc;
		//如果x=8,即该行结束,即换下一行进行递归
		if (fillBlank(y + (x + 1) / 9, (x + 1) % 9, trylist)) {
			return true;
		}
	}
	scene[y][x] = 0;
	//判断trylist中的数字是否都已用完,如果用完表示改行已填写完,无需进行下一步
	if (numloc - trylist >= 8) {
		return false;
	}
	//获取trylist的下一个数字并继续递归填表
	if (fillBlank(y, x, numloc + 1)) {
		return true;
	}	
}

测试运行

运行截图:

输入结果:

输入错误:

性能分析图及改进思路

cpu性能分析截图:

改进思路:

减少调用checkIsLeagal()函数的调用,即在fillblank回溯的过程中,删除无用的回溯分支。

实际花费的时间

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划
· Estimate · 估计这个任务需要多少时间 30 20
Development 开发
· Analysis · 需求分析 (包括学习新技术) 180 300
· Design Spec · 生成设计文档 60 60
· Design Review · 设计复审 (和同事审核设计文档) 30 0
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 10
· Design · 具体设计 120 70
· Coding · 具体编码 150 480
· Code Review · 代码复审 60 40
· Test · 测试(自我测试,修改代码,提交修改) 60 50
Reporting 报告
· Test Report · 测试报告 30 20
· Size Measurement · 计算工作量 30 20
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 60 20
合计 830 1090

《构建之法》1~3章阅后感想

a. 项目/任务有多大?

说明项目的大小,一般用代码行数(Line Of Code)来表示;

针对这个话我有些疑惑:我印象中有三四次被问到我的写的代码行数是多少,我总感觉用代码行数来形容总感觉有些虚,我一直都未对我所写的代码进行统计。在这两年的开发过程中,写的代码很多,但总感觉有一大部分代码都是在重复着复制、粘贴、修改,而真正的重头编写却不多,而且现在开发的框架很多都有代码生成的功能,一些简单的增删查改直接使用生成器就能完成,因此,我该如何统计我的代码行数呢?

此次项目感想

这次项目花的时间相对较长,之前没有接触过Visual Studio 2017开发C++,因此在需求分析 (包括学习新技术) 方面占了较长时间。在编写代码方面,被指针的一些操作也折腾了不少时间。虽然工作两年,但接触的都是一些简单的代码编写,一旦写算法题,就能发现能力确实很差,还是得多练算法题目。

posted @ 2017-10-07 10:50  余国鹏  阅读(259)  评论(0编辑  收藏  举报