提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言`
本文介绍了我关于软件构造实验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.编写代码要养成良好的规范,比如缩进,变量的命名等等。