1.实验目标概述
通过求解三个问题,训练基本Java编程技能,能够利用Java OO开发基本的功能模块,够阅读理解已有代码框架并根据功能需求补全代码,能够为所开发的代码编写基本的测试程完成测试,初步保证所开发代码的正确性。另一方面,利用Git作为代码配置管理的工具,学会Git的基本使用方法。
2.实验环境配置
- 下载安装idea
- 下载安装JDK
原先安装的是jdk8,本次实验可以使用,所以就配置了jdk8。
- 配置junit
idea环境下,在测试代码处自动根据提示导入了junit4。
- 下载安装git
- url地址:
https://github.com/ComputerScienceHIT/HIT-Lab1-2021112055
3.实验过程
3.1Magic Squares
Magic Squares即幻方,是一个n*n的正方形矩阵,它要求每一行,每一列,两条对角线n个数字和的值都要相等。该任务的目标是设计两个函数,第一个函数是isLegalMagicSquare函数,它要判断给定的矩阵是不是幻方,并且会检查文件中的值是否合法。第二个函数generateMagicSquare函数会生成一个矩阵,并调用isLegalMagicSquare函数判断其是否是一个幻方。
3.1.1isLegalMagicSquare()
先读入一行数据,然后以这行的数据个数创建矩阵。
然后循环读入整个矩阵。
若某一行个数与第一行不同。那么要么不是矩阵,要么分隔符不全是\t。
当读入并非正整数的数,返回false。
读完后发现行列数不相等,也返回false。
接下来判断和是否相等。先判断对角线。
若对角线相等,进一步判断各行各列。
全部正确则返回true。
实验结果如下:
提示不是矩阵的有两种可能。某一行个数与第一行不同。要么不是矩阵,要么分隔符不全是\t。
3.1.2generateMagicSquare()
这种创造奇数阶幻方的方法叫做罗伯特法。
具体方法:
把1(或最小的数)放在第一行正中;
按以下规律排列剩下的n^2-1个数:
1)每一个数放在前一个数的右上一格;
2)如果这个数所要放的格已经超出了顶行那么就把它放在底行,仍然要放在右一列;
3)如果这个数所要放的格已经超出了最右列那么就把它放在最左列,仍然要放在上一行;
4)如果这个数所要放的格已经超出了顶行且超出了最右列那么就把它放在它的下一行同一列的格内;
5)如果这个数所要放的格已经有数填入,处理方法同4)。
流程图
数组越界,在i=18时,row=6,col=0
发生了越界
应用程序创建大小为负的数组
处理IOException后,判断生成的是否为幻方。
可见通过这种方法生成的确实是幻方。
3.2Turtle Graphics
根据MIT的实验要求和代码注释,完成TurtleSoup.java中待实现的方法,用Turtle graphics绘制正方形、正多边形并使用JUnit测试、计算方位、计算凸包,实现一个叫Turtle的绘图工具并用其进行创作。
3.2.1Problem 1: Clone and import
访问实验手册给出的URL地址,下载实验P2所需的代码。
在本地创建文件夹,打开git Bash:使用命令git init创建仓库。
使用git add .将文件添加到暂存区;
使用git commit -m \"message\"命令将暂存区的文件提交到git仓库。
使用git push命令将本地仓库推送到Github的仓库上。
更改package,如将package turtle改为package P2.turtle
3.2.2Problem 3: Turtle graphics and drawSquare
要求使用两种方法,forward和turn,画出正方形。
四次循环即可实现。
3.2.3Problem 5: Drawing polygons
实现calculateRegularPolygonAngle
计算正多边形内角公式:180-360/边数
实现drawRegularPolygon
计算出内角,但实际旋转角度为外角,故angle=180-angle
3.2.4Problem 6: Calculating Bearings
实现calculateBearingToPoint
由于atan2所计算的角度是和x轴的夹角
故进行处理
另外将所得角度控制在0-360之间
实现calculateBearings
依次以前一个点为起点,另一个为终点,运用上一个函数计算角度
把角度集合作为返回值
另外每次初始状态的角度是每次角度的叠加
控制叠加值在0-360之间
3.2.5Problem 7: Convex Hulls
我们要利用上一个问题calculateBearingToPoint方法。具体算法如下:
a. 当点集的点的个数小于等于3时,返回点集即可。否则,转b
b. 首先遍历所有的点,找到最左边的点(这个点一定在目标点集中),如果有两个点的x坐标相同,则取y坐标小的点。把这个点设置为极点。
c. 以极点为当前点,当前朝向为0度,顺时针旋转,找到与之夹角最小的点,如果有两个或多个最小转角相同的点,则取最远的点。将这个点设置为极点,并且在原来点集删除这个点。
d. 循环c直到再次遇到第一个极点。
e. 所有设置为极点的点就构成目标点集。
找到左下角的点后,依次选择夹角最小的点。同一方向,选距离更远的点。
这里实际操作没有在原来点集删除,只是在遍历的时候排除那些极点,除了第一个。
3.2.6Problem 8: Personal art
旋转时,每20度画一个十边形。然后移动一段距离,总共画五个。画的过程更富美感,最后的状态可能略显凌乱。不同颜色的感觉差别很大。
3.2.7Submitting
打开Git Bash Here,输入以下命令行
- git add .
- git commit -m “备注” 将暂存区的文件提交到git仓库
(3) git push将本地仓库同步到远程仓库
3.3Social Network
该任务是设计一张社交网络无向图,其中人为图中的点,互为朋友之间的两个人构成一条边。能计算任意两人之间的最短路径。构建的图为无向无权图,可以采用BFS广度优先遍历得到两点间的最短路径。
3.3.1设计/实现FriendshipGraph类
方法有以下三种:
实现addVertex
先判断是否在图的点集合中,若不在则添加到点集中,否则输出“姓名重复”
public void addEdge(Person P1,Person P2){
...
}
添加边要注意判断边的两点是否在其中,不在输出请先添加到图中。
若两点为同一个人,也添加失败。
若本来就已存在这条边,就提示已存在。否则添加从P1到P2的边。
public int getDistance(Person P1,Person P2){
...
}
求距离
若所求的人不在图中,直接返回-1
若求同一个人的距离,直接返回0
用队列实现先广遍历,一层层找P2
若最后没找到,则返回-1
否则返回找到时的层数
3.3.2设计/实现Person类
Person的属性只有一个name,类内的方法有空参构造构造和带参构造,以及获得名字。
3.3.3设计/实现客户端代码main()
直接使用的实验手册上的main()
如果将上述代码的第10行注释掉(意即rachel和ross之间只存在单向的社交关系ross->rachel)则运行结果为
让程序执行,其实际输出结果与期望并不一致,原因是在getDistance函数中将单向关系拓展为了双向关系。
如果将第3行引号中的“Ross”替换为“Rachel”,这其实违反了“Each person has a unique name”的约束条件。更改后,打印出重名提示后便会结束程序。
运行结果:设计/实现测试用例
1 测试addVertex
设计等价类:
{与图中点集名字不同的Person}
{与图中点集名字相同的Person}
名字相同时
2 测试addEdge
设计等价类
等价类 期望结果
(p1,p2)={ 两点都在图中且有双向边} 不重复添加
(p1,p2)={ 两点都在图中且只有单向边} 若已有p1->p2,,则不添加;若无,则添加p1->p2
(p1,p2)={ 两点都在图中且无边} 添加p1->p2
(p1,p2)={ 前者在图中,后者不在图中} 不添加边,提示将p2加入点集中
(p1,p2)={ 前者不在图中,后者在图中} 不添加边,提示将p1加入点集中
(p1,p2)={ 两者都不在图中} 不添加边,提示将p1和p2加入点集中
会提示不在图中的顶点
3 测试getDistance
等价类 期望结果
(p1,p2)={两点都在图中,但其中一个无朋友} -1
(p1,p2)={p1和p2相等 } 0
(p1,p2)={至少一点不在图中 } -1
(p1,p2)={p1和p2之间有通路 } 返回最短路长