高级软件工程第二次作业
项目简介
-
操作系统: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~9个数随机排序作为9*9罗盘的第一行数据
- 同1,也生成一个1~9的随机序列记为T(t1,t2,t3,t4,t5,t6,t7.t8,t9),作为接下来填表的数据
- 由于第一行记录已随机生成,因此我们从第二行还是填写表格,每次遍历T中的每个记录,判断是否符合数独的要求(即:每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复),如果符合要求即填写进入数独表,直到当前行填写完毕。
- 接下来第三行至第九行重复过程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++,因此在需求分析 (包括学习新技术) 方面占了较长时间。在编写代码方面,被指针的一些操作也折腾了不少时间。虽然工作两年,但接触的都是一些简单的代码编写,一旦写算法题,就能发现能力确实很差,还是得多练算法题目。

浙公网安备 33010602011771号