软件构造实验1报告
1 实验目标概述… 1
2 实验环境配置… 1
3 实验过程… 1
3.1 Magic Squares. 1
3.1.1 isLegalMagicSquare(). 1
3.1.2 generateMagicSquare(). 1
3.2 Turtle Graphics. 1
3.2.1 Problem 1: Clone and import 2
3.2.2 Problem 3: Turtle graphics and drawSquare. 2
3.2.3 Problem 5: Drawing polygons. 2
3.2.4 Problem 6: Calculating Bearings. 2
3.2.5 Problem 7: Convex Hulls. 2
3.2.6 Problem 8: Personal art 2
3.2.7 Submitting. 2
3.3 Social Network. 2
3.3.1 设计/实现FriendshipGraph类… 2
3.3.2 设计/实现Person类… 2
3.3.3 设计/实现客户端代码main(). 2
3.3.4 设计/实现测试用例… 3
4 实验进度记录… 3
5 实验过程中遇到的困难与解决途径… 3
6 实验过程中收获的经验、教训、感想… 3
6.1 实验过程中收获的经验和教训… 3
6.2 针对以下方面的感受… 3
1 实验目标概述
本次实验通过求解四个问题,训练基本Java编程技能,能够利用Java OO开发基本的功能模块,能够阅读理解已有代码框架并根据功能需求补全代码,能够为所开发的代码编写基本的测试程序并完成测试,初步保证所开发代码的正确性。另一方面,利用Git作为代码配置管理的工具,学会Git的基本使用方法。
l 基本的Java OO编程
l 基于Eclipse IDE进行Java编程
l 基于JUnit的测试
l
基于Git的代码配置管理
2 实验环境配置
开发环境:Eclipse IDE, Git
测试环境:Junit
运行环境:jdk1.8
过程: 1.安装相应开发环境和开发软件如Java,eclipse等
2.按照手册和实验要求配置环境变量以及参数。
3.配置Junit等,完善Build path。
问题:修改文件路径树的时候由于对与.java文件运行机制的不了解,在成修改时不知道每个文件应该是什么类型的文件(比如哪个文件应该是project哪个文件又应该是package等等),通过了解java文件运行机制最终修改成功。
在配置Junit的Build path浪费了一点时间,最后通过网上学习解决问题。
3 实验过程
请仔细对照实验手册,针对四个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但无需把你的源代码全部粘贴过来!)。
为了条理清晰,可根据需要在各节增加三级标题。
3.1 Magic
Squares
该任务就是通过计算检测实验给予的五个文本是否为幻方,在第二个任务中了解如何生成奇数阶幻方并将其输入到文本中。
3.1.1 isLegalMagicSquare()
首先看到幻方的定义后,要检测是否是幻方,只需测试他的各行列对角线的值是否相等即可。于是第一步我先写简单的检测行列的函数。
1:创建一个二维数组,写测试行列和以及对角线和的代码,并自行给二维数组赋值检测。
2:检查幻方和的代码正确后,我开始将实验包含的五个文本导入,这期间因为初学java,遇到了很多问题,包括如何导入绝对路径,如何按行读取等等,通过百度查询解决。最终检测文本1,2成功。
3:当我检测到文本3的时候,提示我数组越界,在我查看3.txt后,发现某一行少一个数字,于是会产生这种越界,以及文本4,出现浮点数负数,导致无法赋值。
4:进行异常处理,检测行列数以及总数,若不等则提示行列数不相等。
检测由字符向数组赋值的时候是否为正整数,若不为,则提示输入有误。
3,4文本均包含这两个错误。
5:检测5的时候也报行列数不相等,我查看后发现5的文本出现了没有用制表符分割的问题。此问题也会检测导致行列数不相等,我将其划分到了行列数不等的报错里。
3.1.2 generateMagicSquare()
要求2是给一段生成幻方的代码,分析他如何生成的。
1:步骤如下:
n首先为奇数
从第一行最中间的位置开始,行数每次-1,列数每次+1,当到达第一行时,返回到最后一行,到达最后一列,返回到第一列,当写了n的倍数次时,从该数字的下面一个空写,直到全部写完。
2:输入偶数或者负数异常处理报错即可。
3:输入偶数报错是因为在向二维数组赋值的时候,左下角会越界。
输入负数报错是因为不能创建一个大小为负数的数组。
3.2 Turtle
Graphics
实验2主要是利用turtle进行绘制图形操作,以及利用代码完成各种功能
3.2.1 Problem 1: Clone and import
如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。
3.2.2 Problem 3: Turtle graphics and drawSquare
这个问题利用turtle.forward和turn两个函数实现绘制一个正方形,前进四次,转向四次即可完成。
for (int i = 0; i < 4; i++) {
turtle.forward(sideLength);
turtle.turn(90);
}
3.2.3 Problem 5: Drawing polygons
这个问题是画一个正多边形,利用多边形的内角和公式就可以计算出任意正多边形的内角度数,然后再次利用turtle.forward和turtle.turn函数,每次走一定距离,再旋转计算所得的多边形内角数即可。
for (int i = 0; i < sides; i++) {
turtle.forward(sideLength);
turtle.turn(180.00 - angle);
}
3.2.4 Problem 6: Calculating Bearings
1:这个实验分为两部分,第一部分首先实现calculateBearingTopoint ,计算一个点在面对一个方向的时候要到达另一个点需要转向多少度。
我个人是采用了较繁琐的办法,首先用第二个点的坐标减去第一个点的坐标,形成以第一个点为0,0原点,问题化为从原点到达一个点的问题。
我将第二个点分为了 以下几种情况:
x ,y轴上,第一二三四象限中。
因为只能顺时针转动,所以我又按照当前转向角的大小分了情况。
x轴: 在正半轴上,当前角小于正半轴,直接转向即可,大于正半轴,要转一圈回来。
Y轴:就是360-当前转向角即可,注意当前为0时的情况,所以给总体表达式取余即可。
象限:对象限上的角要利用atan函数计算转向角的大小(同时要*180/PI)。
我将其按四个象限划分了
第一象限atan为正,直接atan就是第二个点的角度偏移量。
第二象限atan为负,将atan取绝对值+90度就是第二象限的点的角度偏移量。
第三象限atan为正,atan+180为第三象限的偏移量。
第四象限atan为负,360-|atan|即为第四象限的角度偏移量。
然后将当前角与第二个点偏移量比较,小于就直接顺时针旋转,相减即可,大于就旋转360-差值。
2:第二部分是给出一系列点,计算从第一个点到最后一个点依次经过各个点的转向角。
此部分逻辑也不难,但对我这个不熟悉java的人来说,语法是很大问题,不知道如何调用传进来的数组以及如何生成存储结果的数组,最后通过百度搜索学习习得。
就依次将各个点调用上一部分实现的函数即可,每次的当前角需要重新计算一下,转过的角度之和对360取余即可。
3.2.5 Problem 7: Convex Hulls
这个问题是要我们解决一个名为凸包的问题,就是在一堆点集中找到最外层的点,可以把所有的点包围起来,返回这些最外层点的集合。根据实验指导,我采用了gift-wrapping算法,该算法的过程; 首先在所有点中选择一个最左下的点作为凸包的起点,然后从其他的点中找到一个点使得该点顺时针旋转所转角度最小,加入此点。将此点作为新的起点。并将前一个点到这个点的方位角化为新的初始角度,如此循环。当最后的点与起点重合的时候,凸包完成。
3.2.6 Problem 8: Personal art
绘制个人艺术图案。
3.2.7 Submitting
git add .
git commit -m “P2 commit”
git push origin master
3.3 Social Network
本问题利用图来刻画社交网络,通过addVertex添加成员,addEdge添加关系。构成社交网络,然后计算社交网络中的一些关系。
3.3.1 设计/实现FriendshipGraph类
本任务的目的是用来刻画一个社交网络,所以我选择使用一个Map来存储各个成员的关系,即Map<Person, Set> friendsMap =
new HashMap<Person, Set>();, 其中key部分为社交网络中的一员,所对应的value为一个Set,这个Set中存放了key所认识的所有人,除此之外为了根据规范对于重名的成员作出错误处理,我在此类中定义了一个Set:private Set vertexString = new
HashSet(),它被用来存储所有已经出现过的人名。接下来就是三个方法的具体实现,在public
boolean addVertex(Person person)的实现中,我会判断参数person对象的名字是否已经出现在了vertexString中,如果已经出现则输出 "Each person must have a unique name"并且返回false,否则我们就在friendsMap中添加组键值对,键为person,值的Set初始化为空,并将person的名字添加到名字集合vertexString中,返回true;
public boolean
addEdge(Person person1, Person person2)方法首先会判断person1, person2是否已经在vertexString中,如果不存在的话则调用addVertex将其添加进去,如果存在,则将person2添加到friendsMap中person1所对应的Set中作为person1所认识的人。
public int
getDistance(Person person1, Person person2)方法的实现采用的迪杰斯特拉算法,固定一个头节点,然后遍历所有点的边,将权值最小的边加入集合,并同时以其为头节点在计算剩下点的距离,如果当前距离小于修改距离,那么部进行修改,否则更新最短距离,最后遍历完所有点就可以求出最小边长度。.
3.3.2 设计/实现Person类
Person定义一种结构体,其中保存节点(人)名称、保存点的标号、保存邻接顶点的指针
public class Person {
String name;
int lable = 0;
Person next = null;
public Person(String name){
this.name = name;
}
}
3.3.3 设计/实现客户端代码main()
main函数调用实验报告中的例子进行测试。
3.3.4 设计/实现测试用例
我添加了p1-p10十个人加入到社交网络,再加入一些边,
然后对这些边构成的社交网络进行测试。
测试分成四类:当不能到达,不为通路,没有关系时候,返回-1
当可以到达,返回距离
当找自己,返回0.
当重名,提示。
遇到的难点
解决途径
初学java,许多简单的语法问题让我一路受阻,总结一下自己遇到的语法问题和一些简单的问题。
1.System.out.print()中输出多个变量的时候要用+号,每一个之间都要加上,不能忽略。
2.String.length问题,对于一个字符数组,要用string.length,而不是string.length(),此适用于字符串。
3.实验一的第一个实验中,我读取了每一行后,然后用.split("\s+")分割,但每一行后总多余一个空格导致我后续赋值出错,最终百度使用了split("\s+")解决,不知道为什么我的后面会读取多出一个空格。
4.关于上述3是我的问题,实验要求使用\t分隔,我擅自采用了 \s+分隔,在我检测5.txt的时候,一开始发现总是成功的,一度认为5.txt是正确的。后来在我改进成\t分隔时,发现5.txt出现错误,行列数不相等! 于是我将5.txt的文本检查一遍发现,该文本中存在未使用\t分割的地方,所以文本分割后行列数的计算时会发现不相等! 于是找出文本5也是错误的。(readline后的空格使用了String.tirm()消除掉)