软件工程实践2019第三次作业
1.Guthub项目地址:
https://github.com/cai0326/hello-world
2..PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
Estimate | 估计这个任务需要多少时间 | 765 | 1065 |
Development | 开发 | 60 | 60 |
Analysis | 需求分析 (包括学习新技术) | 120 | 180 |
Design Spec | 生成设计文档 | 60 | 60 |
Design Review | 设计复审 | 30 | 30 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 45 | 45 |
Design | 具体设计 | 30 | 60 |
Coding | 具体编码 | 120 | 300 |
Code Review | 代码复审 | 30 | 30 |
Test 测试 | (自我测试,修改代码,提交修改) | 30 | 60 |
Reporting | 报告 | 60 | 60 |
Test Repor | 测试报告 | 60 | 60 |
Size Measurement | 计算工作量 | 30 | 30 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 60 |
合计 | 765 | 1065 |
3.思路描述
文件输入输出
刚开始思考这道题目的时候,就感觉从文件中提取信息,之后将答案写入文件会是我要解决的第一个问题。因为之前从来没有从文件读取信息的基础(以前没有好好学习的锅),加上这两周才开始学习java,所以我开始从网上和书上查找java读取文件的方法。最后在书上学习了BufferReader和BufferWriter类,采取按行读取的方法。将文件内容以按行,字符串的形式读取,在将字符串转化成数组进行求解,最后再将数组转化成字符串进行写入。(这个方法有点呆,不过实在没有找到其他办法)
由于本次题目可能要一次求解多个数数独,在文件中两个数独之间空一行,因此我采取了循环的方式读取文件,在第一次循环中将第一个数独读出,进行求解并将求解的答案存入一个字符串,之后由于第二次读取又从第一行开始读取,因此在循环中加入了判断,选择每次循环所要读取的数独。(又是一个很笨的办法)
求解数独
我选择从九宫格入手,分为回溯法以及判断填入的数字是否合法的判断两个部分。对于数字合法性的判断我选择将判断行合法、列合法和宫合法分别创建boolean类型数组进行判断。首先对数独数组进行遍历搜索,对3个Boolean数组进行装载,对数独中不为的位置进行记录,当a[i][j]不为0时,分别在3个数组中进行行,列,宫中已经存在值为a[i][j]的数,在对应位置进行赋值ture判断。在回溯函数中进行判断时只需要进行对3个Boolean数组中对应位置的值是否为同时不为true判断所填的数是否合法。
例如当a[i][j]!=0,则令int val = arr[i][j] - 1;rows[i][val] = true;cols[j][val] = true;blocks[k][val] = true;其中的k为相应位置宫的序号。
在实现完9宫格之后,扩展到其他宫格的问题在不用考虑宫和考虑宫,以及需要考虑的宫中宫的序号的计算的区别。我将本次的数独分为2大类,第一类为不考虑宫类(3,5,7),第二类为考虑宫类(4,6,8,9)。其中为了计算考虑宫类中宫的序号,又将其分为2小类,4和9一类,6和8一类。
函数关系
在主类中进行文件的输入输出和boolean数组的创建和装载,在主类外写一个回溯法求解数独函数供主类直接使用。
4.代码展示
数独读取存入整形数组
for(l=1;l<=n;l++) {
try {
String str=null;
FileReader fr=new FileReader(file1);
BufferedReader bufr=new BufferedReader(fr);
//按行循环读取文件
for(i=0;i<(m+1)*l-1;i++)//文件的第(m+1)*l-2行为本次循环所要读取的数独的最后一行(文件行数从0开始)
{
str=bufr.readLine();//按行读取
String[] strs = str.split(" ");
for (j=0;j<m;j++){
if((i-(l-1)*(m+1))>-1) {//文件的第(l-1)*(m+1)行为本次循环所要读取的数独的第零行
arr[i-(l-1)*(m+1)][j]=Integer.parseInt(strs[j]);//将字符类型转换为整形
}
}
}
bufr.close();
}catch(Exception e) {
e.printStackTrace();
}
}
数据装载
for (i = 0; i < arr.length; i++) {
for (j = 0; j < arr.length; j++) {
if (arr[i][j] != 0) {
if(m==6||m==9) {
a=m/3;
b=i/a*a;
k=j/3+b;
}//分解6宫格和9宫格的宫
else if(m==4||m==8) {
a=m/2;
b=i/a*a;
k=j/2+b;
}//分解4宫格和8宫格的宫
int val = arr[i][j] - 1;
rows[i][val] = true;
cols[j][val] = true;
blocks[k][val] = true;
}
}
}// 数据装载完毕
回溯函数
public static boolean DFS2(int[][] arr,int m, boolean[][] cols, boolean[][] rows,boolean[][] blocks) {
int a,b,k=0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < m; j++) {
if (arr[i][j] == 0) {
if(m==6||m==9) {
a=m/3;
b=i/a*a;
k=j/3+b;
}
else if(m==4||m==8) {
a=m/2;
b=i/a*a;
k=j/2+b;
}
for (int l = 0; l < m; l++) {
if (!cols[j][l] && !rows[i][l]&& !blocks[k][l]) {// l对于的数字l+1没有在行列块中出现
rows[i][l] = cols[j][l]= blocks[k][l]=true;
arr[i][j] = 1 + l;// 下标加1
if (DFS2(arr,m, cols, rows,blocks))
return true;// 递进则返回true
rows[i][l] = cols[j][l] = blocks[k][l]=false;// 递进失败则回溯
arr[i][j] = 0;
}
}
return false;// a[i][j]==0时,l发现都不能填进去
}// the end of a[i][j]==0
}
}
return true;// 没有a[i][j]==0,则返回true
}
5.性能测试
6.代码测试
7.心路历程与收获
心路历程:
在拿到这次题目的时候就感觉到本次任务不简单,需要花费时间和心思去做。果然对于java的不熟悉和学习全新知识的困难让我频频触壁,但还是渐渐地通过自己的努力和同学的帮助下初步完成了本次编程。在连续三天平均5~6小时的学习中,又有学习时的枯燥,又有学习后的满足和收获的喜悦。
收获:
在编写代码前一定要先构思好,最好把自己的思路先记录下来,避免在写代码的过程中发现设计不合理无法继续进行。
遇到不会的知识点一定要查阅资料或者请教同学,一步一步的进行学习。
学习到了一些以前没接触的知识:文件的输入输出,java的各种基础知识!![]