软件工程实践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的各种基础知识!![]

posted @ 2019-09-25 21:21  csf  阅读(157)  评论(0编辑  收藏  举报