【软件构造】实验一的心得体会

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言`

本文介绍了我关于软件构造实验1的一些学习心得和经验教训。


一、Magic Squares

1.任务要求

Magic Squares即幻方,是一个n*n的正方形矩阵,它要求每一行,每一列,两条对角线n个数字和的值都要相等。该任务的目标是设计两个函数,第一个函数是isLegalMagicSquare函数,它要判断给定的矩阵是不是幻方,并且会检查文件中的值是否合法。第二个函数generateMagicSquare函数会生成一个矩阵,并调用isLegalMagicSquare函数判断其是否是一个幻方。

2.isLegalMagicSquare()

这个任务的关键是判断从文件中输入的数据是否合法,不合法的情况包括:行列数不相等,并非矩阵,某些数字不是正整数,数字之间并非使用\t分割等。

1.BufferedReader

在这个任务中,我们要读取文件中的内容,那么就需要调用BufferedReader方法。在这里我对BufferedReader方法进行介绍。
BufferedReader是为了提供读的效率而设计的一个包装类,它可以包装字符流。可以从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。、
在这里我们重点介绍BufferedReader类里的两个方法。

read
int read()方法,每次可以读取到一个字符(以int 类型表示),不过因为返回的是int类型的,所以要强制类型转换成char类型才能打印该字符。

readLine
String readLine()这个方法一次可以读取一个文本行,返回的直接就是这一行的字符串,如果读到行尾了就返回null。
这个方法就是我们在这个任务中所需要的。

static boolean isLegalMagicSquare(String fileName) throws IOException {
		String filename = fileName;
		int row = 0;// 记录矩阵的行数
		try {
			BufferedReader br = new BufferedReader(new FileReader(filename));
			while (br.readLine() != null) {
				row++;
			}
			br.close();// 关闭文件
		} catch (IOException a) {
			System.out.println("ERROR! " + filename + " 读取文件错误");
			return false;
		}

在上面的代码片段中,我调用了readLine方法,从给定的文件中一行一行读取字符,在这里要注意几个点。一是readLine读到行尾就返回了null,我们用此作为循环判断条件。而是调用完后,要记住关闭文件,也就是调用close方法。

2.split

在java中split方法把字符串按照指定的分割符进行分割,然后返回字符串数组。

while ((myLine = BR.readLine()) != null) {
			 line = myLine.split("\t");//调用split,在每个\t处分割

在给定的文件中,数字与数字之间用\t分割开。用myLine保存文件中一行字符串,在调用\t方法对字符串进行切割,存放到line数组中。举个例子,myline=“65\t43\t7\t”,调用split方法后,line[0]=65,line[1]=43,line[2]=7。

if (myLine.split(" ").length > 1) {
				System.out.println("ERROR! " + filename + " 数字之间并非用\\t分割");
				BR.close();
				return false;
			}

而如果数字与数字之间不是用\t分割,而是用空格分割,那我们仍然可以用split方法,如上面代码片段所示。用split对数据在空格处进行分割,如果分割后得到的数据大于1(也就是说明有的数据并未用\t分割),则返回false.

3.generateMagicSquare

这个问题的关键是读懂给定的代码段是如何生成一个矩阵的。下面给出了代码以及注释,要注意这里的n必须是一个正整数且是奇数。

int magic[][] = new int[n][n];
		int row = 0, col = n / 2, i, j, square = n * n;
		// 将1-square这n*n个元素填写到矩阵中
		for (i = 1; i <= square; i++) {
			magic[row][col] = i;// 首先填写第一行正中间的数,之后向右上方填写
			if (i % n == 0)
				row++;// 每填入n个数,第n个数的右上方就是第一个数,那么就需要换到下一行填写
			else {
				if (row == 0)
					row = n - 1;// 第一行的右上方为最后一行
				else
					row--;// 右上方的行数比当前的行数少一
				if (col == n - 1)
					col = 0;// 最后一列右上方为第一列
				else
					col++;// 右上方的列数比当前的列数多一
			}
		}

二、Turtle Graphics

1.任务要求

我们通过对Turtle发出命令,观察它的移动轨迹(也就是我们所需要的画的图像),在这个任务中我们需要完成:画一个正方形,画一个多边形,计算夹角,计算凸包。

2.Calculating Bearings

前面的几个问题都很简单,就不在这里复述了。
calculateBearingToPoint 这个方法是要实现从当前点的当前朝向转多少度能朝向目的点。这个只需要借助y轴作为中间量即可。首先计算当前点和目的点的连线向量与y轴的夹角,再减去当前点的当前朝向与y轴的转换即可,这里注意旋转都是顺时针旋转,注意正负角。

public static double calculateBearingToPoint(double currentBearing, int currentX, int currentY,
                                                 int targetX, int targetY) {
    	double angle = 90.0 - Math.atan2(targetY - currentY,targetX - currentX) / Math.PI * 180 ;//计算目的点与当前点连线的向量与y轴夹角,弧度转角度
    	if(angle >= currentBearing	)   
    		return (angle - currentBearing ); //顺时针转
    	else return (angle - currentBearing + 360 );//度数为负值,加上360度,顺时针转
    }

这里的关键,一是调用Math.atan2方法计算从 X 轴正向逆时针旋转到点 (x,y) 时经过的角度。二是注意,这里的方向角都是顺时针旋转得到的,所以如果求出来的是个负角,不能按逆时针看待,要加360度。

3. Convex Hulls

这个问题是凸包问题,即求一组最小的点集,使得这些点集依次连线能够把所有的点给包围起来。这个问题也是我认为本次实验中最难的一个问题。我们要利用上一个问题calculateBearingToPoint方法。具体算法如下:
a. 当点集的点的个数小于等于3时,返回点集即可。否则,转b
b. 首先遍历所有的点,找到最左边的点(这个点一定在目标点集中),如果有两个点的x坐标相同,则取y坐标小的点。把这个点设置为极点。
c. 以极点为当前点,当前朝向为0度,顺时针旋转,找到与之夹角最小的点,如果有两个或多个最小转角相同的点,则取最远的点。将这个点设置为极点,并且在原来点集删除这个点。
d. 循环c直到再次遇到第一个极点。
e. 所有设置为极点的点就构成目标点集。

三、Social Network

1.任务要求

该任务是设计一张社交网络无向图,其中人为图中的点,互为朋友之间的两个人构成一条边。能计算任意两人之间的最短路径。构建的图为无向无权图,可以采用BFS广度优先遍历得到两点间的最短路径。
这个任务,我认为难点不在于BFS算法,而是类中要设置什么字段,方法能更好的完成任务。

2.设计FriendshipGraph类

private ArrayList<Person> allPeople = new ArrayList<Person>();//所有人的集合
private ArrayList<String> allName = new ArrayList<String>();//所有名字的集合

首先设置了一个List(allPeople)用来存储所有人,又设置了一个List(allName)用来存储姓名。之所以设置两个List是因为人的名字(name)和人的实例的名称不同。比如
在这里插入图片描述
一个Person实例rachel,他的名字(name)为Rachel.

3.设计Person类

private String name ;//姓名
private ArrayList<Person> friends = new ArrayList<Person>();//朋友列表

Person类设置了一个name字段用来保存名字,friends列表用来保存一个人的朋友,还有这两个字段的get方法。同时实现了方法addFriend.用来往friends列表里添加个体。


总结

1.首先要搞清楚任务的需求,不能一开始就盲目的做,要大体上了解整个任务的目的是什么。
2.学会使用Java强大的类库,善于查询Java API文档,上网查询。很多情况下,不需要自己实现代码,只需要调用库里已有的方法即可,就比如队列的相关操作。
3.学会了git的相关操作,并且了解到了git的优势,养成了经常将代码提交到仓库的习惯。
4.编写代码要养成良好的规范,比如缩进,变量的命名等等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值