软件工程实践第二次作业
作业链接
1.github链接
2.PSP
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | · 计划 | 40 | 70 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 40 |
Development | · 开发 | 500 | 680 |
· Analysis | · 需求分析 (包括学习新技术) | 100 | 150 |
· Design Spec | · 生成设计文档 | 0 | 0 |
· Design Review | · 设计复审 (和同事审核设计文档) | 0 | 0 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 10 |
· Design | · 具体设计 | 60 | 80 |
· Coding | · 具体编码 | 300 | 350 |
· Code Review | · 代码复审 | 30 | 50 |
· Test | · 测试(自我测试,修改代码,提交修改) | 100 | 150 |
Reporting | · 报告 | 150 | 180 |
· Test Report | · 测试报告 | 100 | 110 |
· Size Measurement | · 计算工作量 | 30 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 1490 | 1920 |
3.解题思路描述。即刚开始拿到题目后,如何思考,如何找资料的心路历程。
(刚开始拿到题目之后)
看到这个题目的时候,内心是非常拒绝的,一开始看到了数独,有点茫然,对于数独的了解并不大深,通过了解,原来就是九宫格里的每行每列要有1-9的数字,并且不重复,每个宫里也是如此,没能想到合适的方法,就开始了漫漫找资料的历程。一开始搜索的关键字就是“随机生成数独”,利用深度优先遍历的方式,然后通过判断每个点是否正确摆放生成数独,对于这个方法的理解有些困难,然后继续找看看有没有其他的方法。首先随机数法对于本次的题目来说肯定是不大合适的,数字庞大效率低下,后面又找到了回溯法和置换法两种方法,觉得回溯法这个方法比较好理解,于是就选择了使用这个方法。
回溯法
先设置一个全为0的九宫格,然后从第一个为0的格子开始填入随机数,并判断是否满足数独的要求(即每行每列没宫不可有重复数字),继续向下查找为0格子填入,如果没有可选数,进行回溯,换掉前面的数字,继续执行,以此类推,知道81个格子全不为零的时候,就生成了一个数独。下面是具体代码
4.设计实现过程
分为四个函数:
5.代码说明。
rightplace函数:
bool sudokutest::rightplace(int g, int h)//检测九宫格里的每个数字是否符合数独要求
{
int row, col;
row = g / 9;
col = g % 9;
int i, j;
for (i = 0; i < 9; i++) //对该数字所在的行查找是否有相同的数字
{
if (sudoku[row][i] == h)
return false;
}
for (i = 0; i < 9; i++) //对该数字所在的行查找是否有相同的数字
{
if (sudoku[i][col] == h)
return false;
}
int a, b;
a = row / 3;
b = col / 3;
for (i = a * 3; i < a * 3 + 3; i++) //在每一个宫里判断是否有相同的数字出现
{
for (j = b * 3; j < b * 3 + 3; j++)
{
if (sudoku[i][j] == h)
return false;
}
}
return true;
}
put函数:
void sudokutest::put(int n)
{
int row, col;
row = n / 9;
col = n % 9;
int i;
if (n == 81)//达到81,说明九宫格已经被填满
{
pd = true;
return;
}
if (sudoku[row][col] != 0)//找到没有被填的格子
{
put(n + 1);
}
else
{
if (n % 9 == 0)//每一行将数组随机调换
random_shuffle(&(a[0]), &(a[9]));
for (i = 0; i < 9; i++)
{
if (rightplace(n, a[i]))
{
sudoku[row][col] = a[i];
put(n + 1);
if (pd)
return;
sudoku[row][col] = 0;
}
}
}
}
main函数主要:
int main(int argc, char *argv[])//实现可以从cmd输入sudoku.exe -c 1000格式
{
int i, j, temp = 0;
int k = 0, num = 0;
int p = 0;
stringstream stream;
string na,ne;
int n;
if (argc!=3)
{
cout << "ERROR!!!more or less sentences" << endl;
return 0;
}
else
{
ne = argv[1];
if (ne == "-c")
{
na = argv[2];
int l = na.length();
for (int m = 0; m < l; m++)//判断输入的字符串是不是纯数字
{
if (na[m] <= 57 && na[m] >= 48)//数字0-9的ascii码为48-57,若发现数字,p就加一
{
p++;
}
}
if (p != l)//如果最后的p与字符串长度不相同,就说明输入的字符串不是纯数字
{
cout << "please enter an integer" << endl;
return 0;
}
stream << na;//将字符串转换成数字
stream >> n;
stream.clear();
freopen("./sudoku.txt", "w", stdout);
while (n--)
{
sudokutest s;
s.first();
pd = false;
s.put(0);
s.print();
}
}
else
{
cout << "Your input format is wrong!!!" << endl;
}
}
}
最主要的就是这三个代码,put函数使用回溯方法进行数字的放入,right place用来判断每行每列每宫是否有重复,是否符合数独的规定。因为测试要使用cmd,一开始不知道要使用argc ,argv[]这种方法,不能实现sudoku.exe -c 1000这样语句的实现。由于会出现-c abc或者-c 12r这样的错误语句,故需要判定输入的字符串是否为纯数字。
6.测试运行。
cmd输入测试:
输出结果:
7.效能分析
直接用该代码进行性能测试,应该是不行的,就很奇怪
后面觉得应该是main函数的问题,就把它改成了直接输入的形式,去掉了argc,argv[]方法进行测试,测试的数量为1000
从中可以看到print函数占用的最大,一开始我是使用cout进行输出的,之前听说过进行大量输出的时候,printf好像效率会高一点,于是我就把输出改成printd
emmmm,就快了三秒,然后就继续看看还有什么更高效的输出方式,搜到了putchar方法
从时间量上来看,putchar的时间还比printf多了一点点,一脸茫然。不知道还有什么其他的可以优化的方法了。