软件工程实践2017第二次作业
Github连接:https://github.com/zora02/object-oriented/tree/master/BIN
https://github.com/zora02/object-oriented/blob/master/shuduku.cpp
一、项目相关要求
利用程序随机构造出N个已解答的数独棋盘 。
输入
数独棋盘题目个数N(0< N <= 1000000)
输出
随机生成N个不重复的已解答完毕的数独棋盘,并输出到sudoku.txt中。
二、遇到的困难及解决方法
构造数独:最开始想通过随机数先生成一个九宫格,再删除掉里面的重复数,再求解。可是这个方法我写出来以后经常进入死循环,试了很多办法,就是改不出bug(╥﹏╥),而且这个代码效率比较慢。后来我去百度知道了回溯法构造数独,觉得这个方法效率高些,并学习了来使用。
参考代码:http://blog.csdn.net/hustspy1990/article/details/7464698
(其实看了这个代码以后,我深受影响,把自己的设想都推翻了,总觉得自己的方法不太好,想学习这个方法。我认真理解了这个方法以后,就用了,但是代码写出来就差不多了,我挺害怕被判抄袭的,我不知道学习了这个方法用起来,算不算抄袭(´・_・`))
生成随机数:在生成随机数的时候,最开始我不会使用随机数,就去查资料:
http://www.cnblogs.com/afarmer/archive/2011/05/01/2033715.html
rand()产生的随机数在每次运行的时候都是与上一次相同的。若要不同,用函数srand()初始化它。可以利用srand((unsigned int)(time(NULL))的方法,产生不同的随机数种子,因为每一次运行程序的时间是不同的。
因为是生成多个随机数独,所以我把构造数独的函数放到循环里去生成,结果发现每次产生的数独都一样,最开始以为是随机数的随机性没有那么强,可是这与资料里说的用time初始化种子每次都不一样相矛盾。我就去尝试把随机生成的不完整数独输出查看,发现每次输出的数独并不一样。以为自己构造方法错了,可是我觉得这个方法不影响不同数独的随机性。
去查了资料发现:
应用在一个FOR循环中,取到的多个随机值就基本相同的原因如下:
用系统时间做随机种子并不保险,如果应用程序在一个较快的计算机上运行,则该计算机的系统时钟可能没有时间在此构造函数的调用之间进行更改,Random 的不同实例的种子值
原来是srand()不能放在for循环内,应该放到外面初始化种子才不会重复。中途还想要用guid生成随机数,但是好像在c#中适用,c++用的很少,不太方便的样子。
使用命令行编译:由于我没有windows系统的电脑,自己电脑装双系统,又装vs的话系统很容易崩掉,惨痛教训,所以我的IDE是Xcode。作业里要求的用命令行进行编译,我是借用别人的电脑进行尝试和修改的,但是好像不太成功,-c可以编译,但是好像无法识别后面的数,数目要输入两遍(T_T),查了很久资料也不知道怎么解决。
三、关键代码
检查九宫格内数是否合法:利用bool函数判断
bool shudu_check(int shudu[][9],int x,int y)
{
int i,j;
int temp = shudu[x][y];
//检验同一行数是否有重复
for(i=0;i<9;i++)
{
if(i!=x && shudu[i][y] == temp)
return false;
}
//检验同一列数是否有重复
for(j=0;j<9;j++)
{
if(j!=y && shudu[x][j] == temp)
return false;
}
//检验小九宫格内数是否有重复
int x0=(x/3)*3;
int y0=(y/3)*3; //(x0,y0)是(x,y)所属小九宫格内左上角第一格的坐标
for (i = x0; i<x0+3; i++)
{
for(j=y0; j<y0+3; j++)
{
if(i!=x && j!=y && shudu[i][j]==temp)
return false;
}
}
return true;
}
构造数独:回溯法,基本思想就是深度优先搜索(DFS),对不完整随机数独每个数进行检查,数满足条件就检查下一个数,不满足条件就退回,并把数置0,重新赋予满足条件的数。
void shudu_generate(int flag)
{
int shudu[9][9]={0};
int x, y;
shudu[0][0]=4;
//生成随机数赋值给九宫格
for(int i=0; i<9; i++)
{
int a=rand()%81;
if(a/9!=0 || a%9!=0) //限制shudu[0][0]为固定值
shudu[a/9][a%9]=i+1;
}
//回溯法构造数独
int t=1;
while(flag==1)
{
x=t/9;
y=t%9;
while(flag==1)
{
shudu[x][y]++;
if(shudu[x][y]>9) //回溯,把数置零
{
shudu[x][y]=0;
t--;break;
}
else if(shudu_check(shudu,x,y)==true)//合法,检查下一个数
{
t++;break;
}
}
if(t==81)
{
shudu_print(shudu);
cout<<endl;
flag=0;
}
}
return;
}
四、测试运行及性能分析
(先在这里解释一下,我代码和博客的编写都是在Mac系统下完成的,只是借用别人的windows电脑编译完成,生成exe文件提交,所以我测试运行与性能分析都是由Xcode完成,请见谅T_T)
测试运行
测试结果截屏
性能分析
(由于种种原因我借用的windows电脑里的vs软件无法生成性能分析报告,好像是缺少一个项目,但是我下了sp1,还是不行,所以我尝试着用xcode,但是我好像不太会用)
其实我没有搞懂性能分析报告,看得有点迷,也不知道该如何下手去修改代码(>_<)
也没有在网上找到一些教程,更多关于xcode性能测试的教程都是关于ios开发的
只是找到这篇http://blog.csdn.net/ggghub/article/details/50325637 可能是自己知识储备太少,我基本看不太懂这个性能分析该如何使用,所以我没有去优化代码,真的不知道怎么改(T_T)但是我试着去看看运行比较大数据的时候CPU的情况,好像不太乐观??CPU占比有点大是这个意思吗?我觉得可能还是构造数独函数消耗最大。
这是刚开始测试num=1000的情况:
五、PSP
PSP2.1 | Personal Software Process Stages | 预估耗时 | 实际耗时 |
---|---|---|---|
Planning | 计划 | 1.5h | 3-4h |
· Estimate | · 估计这个任务需要多少时间 | 2days | 3days |
Development | 开发 | 2h | 3h |
· Analysis | · 需求分析 (包括学习新技术) | 3-4h | 3-4h |
· Design Spec | · 生成设计文档 | 1h | 2-3h |
· Design Review | · 设计复审 (和同事审核设计文档) | 30mins | 1h |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30mins | 30mins |
· Design | · 具体设计 | 1h | 1h |
· Coding | · 具体编码 | 2h | 3h |
· Code Review | · 代码复审 | 30mins | 1h |
· Test | · 测试(自我测试,修改代码,提交修改) | 1h | 2h |
Reporting | 报告 | 1h | 1.5h |
· Test Report | · 测试报告 | 10mins | 1h |
· Size Measurement | · 计算工作量 | - | - |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 1h | 1.5h |
合计 |
由于一些事情,完成作业的时间跨度蛮大的,所以没有认真的计时,我只是写了个大概的时间,没有办法具体合计出来,请见谅。