哈工大 软件构造 Lab1 2022

在这里插入图片描述

2022年春季学期
计算学部《软件构造》课程

**Lab 1实验报告
**

姓名李启明
学号120L021920
班号2003006
电子邮件1094583745@qq.com
手机号码

目录

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

实验目标概述

本次实验通过求解三个问题,训练基本 Java 编程技能,能够利用 Java OO 开

发基本的功能模块,能够阅读理解已有代码框架并根据功能需求补全代码,能够

为所开发的代码编写基本的测试程序并完成测试,初步保证所开发代码的正确性。

另一方面,利用 Git 作为代码配置管理的工具,学会 Git 的基本使用方法。

基本的 Java OO 编程

基于 Eclipse IDE 进行 Java 编程

基于 JUnit 的测试

基于 Git 的代码配置管理

实验环境配置

(简要陈述你配置本次实验所需开发、测试、运行环境的过程,必要时可以给出屏幕截图。

特别是要记录配置过程中遇到的问题和困难,以及如何解决的。)

本次实验开发测试运行的环境为IDEA,在配置环境的过程中,主要遇到的是原来的版本Java JDK8与实验要求的JDK11不符,通过在IDEA上简单的调试即可解决上述问题。

在这里给出你的GitHub Lab1仓库的URL地址。

https://classroom.github.com/a/K_B5NllB

实验过程

请仔细对照实验手册,针对四个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但无需把你的源代码全部粘贴过来!)。

为了条理清晰,可根据需要在各节增加三级标题。

Magic Squares

幻方问题,首先考虑的是如何读写文件,其次是如何判断是否是幻方。

读:主要是读取文件需要

File file = new File(fileName);
FileReader reader = new FileReader(file);
BufferedReader bReader = new BufferedReader(reader);

写:在工作台和在写6.txt的时候需要

工作台键入

Scanner sc = new Scanner(System.in);

写6.txt

File file = new File(“src/P1/txt/6.txt”);
PrintWriter output = new PrintWriter(file);
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
output.print(magic[i][j] + “\t”);
output.println();
}

isLegalMagicSquare()

按步骤给出你的设计和实现思路/过程/结果。

首先判断格式是否正确。格式判断包括是否为矩阵、输入的内容是否合法。

用length[]来记录每一行的长度,如果后一行不等于前一行,要么说明不是矩阵,要么说明不使用/t的格式;其次如果格式正确,那么验证格式内容,如果内容不是/d或者为负数或者与之前的元素重复,均会报错。

其次判断是否是幻方。这个任务可以被分为三部分:

  1. 主对角线是否和次对角线相等?
  2. Sum_row是否相等?
  3. Sum_collom是否相等?

通过设计循环即可进行判断,难度不大。

if (row != col)
return false;
else
n = col;

for (i = 0; i < n; i++) {
sum_row += Msquare[i][i];
sum_col += Msquare[n - i - 1][i];
}

if (sum_row == sum_col)
s = sum_row;
else
return false;

for (i = 0; i < n; i++) {
sum_row = 0;
for (j = 0; j < n; j++) {
sum_row += Msquare[i][j];
}
if (sum_row != s )
return false;
}
for (i = 0; i < n; i++) {
sum_col = 0;
for (j = 0; j < n; j++) {
sum_col += Msquare[j][i];
}
if (sum_col != s)
return false;
}

generateMagicSquare()

这个函数体现了一种实现幻方的方法。

首先初始化,生成一个空矩阵,元素第一个数组定位在Row=0,Col=n/2处。

然后通过n*n次循环填充上述矩阵,将矩阵的[row, col]位置填充为i,然后i++,随后使Row–,Col++,但是要注意不能使数组越界,因此添加了很多条件分支进行控制。

最终可以将填好的幻方打印出来,或者通过printwritter将其打印到全新的文件中利用上一问的函数来检验是否为幻方。

上述函数的流程图如下图所示:

在这里插入图片描述

如果输入的 n 为偶数,函数运行之后在控制台产生以下输出:

Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 12

at MagicSquare.generateMagicSquare(MagicSquare.java:17)

at MagicSquare.main(MagicSquare.java:121)

这是因为输入偶数的话,上述的算法会失灵,存在数组越界的情况,抛出异常。

如果输入的 n 为负数,函数运行之后在控制台产生以下输出:

Exception in thread “main” java.lang.NegativeArraySizeException

at MagicSquare.generateMagicSquare(MagicSquare.java:11)

at MagicSquare.main(MagicSquare.java:121)

这是因为正常情况下数组下标不可能出现负数,因此程序抛出异常。
在这里插入图片描述

程序经过改写后,可以实现上述功能,并且将新生成的幻方写入了6.txt调用之前的isLegalMagicSquare()方法来检验是否为幻方;并且如果输入不合法,会返回False,“优雅”地退出。
在这里插入图片描述

Turtle Graphics

此题旨于根据提示一步一步实现基本功能,逐层深入,通过完成一些比较简单的方法,逐渐添加功能,最后得到一个较为复杂的方法。

Problem 1: Clone and import

(如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。)

在GitHub上可以获取完整的P2文件夹,下载zip文件解压到当前IDEA工作文件夹,注意这个时候需要修改每个包的引用(因为路径发生了变化);在本地创建仓库非常简单,找到父文件夹,打开Git bash并输入git init指令即可完成初始化。接下来就可以利用add、commit等指令来管理文件;也可以通过连接GitHub上的远程仓库将master push到remote端。

Problem 3: Turtle graphics and drawSquare

乌龟画板的程序比较好理解,首先应该查看turtle类,看一看它为我们提供了哪些方法,例如:forward、turn、color等。基于此,绘制一个Square只需要一个循环,每次先前进side长度,在turn 90°,循环四次即可。

Problem 5: Drawing polygons

该问题要求绘制正n边型,那么我们通过数学公式可以推导出正N边型的内角,该角的补角即为每次turn的角度。

Problem 6: Calculating Bearings

double angle = Math.toDegrees(Math.atan2(targetY-currentY,targetX-currentX ));

计算每次方位改变所需要的夹角,这里我们选择math.atan2函数,通过角度的转化可以确定最终的Bearings。这样我们可以得到每两个点之间的角度的改变,得到方法calculateBearingToPoint;而要求我们做的Calculating Bearings给出了一系列的点,我们只需要依次调用上述的函数即可计算出这个关于角度的序列。

public static List<Double> calculateBearings(List<Integer> xCoords, List<Integer> yCoords) {
List<Double> angles = new ArrayList<>();
double currentBearing = 0.0;
int currentX = xCoords.get(0), currentY = yCoords.get(0), targetX, targetY;
int length = xCoords.size();

for (int i = 1; i < length; i++) {
targetX = xCoords.get(i);
targetY = yCoords.get(i);
angles.add(calculateBearingToPoint(currentBearing, currentX, currentY, targetX, targetY));
currentBearing = angles.get(i - 1);
currentX = targetX;
currentY = targetY;
}

return angles;
}

注意对点的初始化。

Problem 7: Convex Hulls

最小凸包问题

查阅资料,常见的解决最小凸包算法有两种卷包裹法和Graham-Scan算法。在这里选取了比较简单的卷包裹算法。

在这里插入图片描述

以上述图为例,假设1为起点,那么下一个点应该是距离该点极角最小的点,不难看出,这个点应当是5;如果距离该点的最小极角有多个点,那么应当取距离该点距离最短的(因为我们求的是最小凸包)。以此类推,直到最后回到了初始的点为止。这样凸包内的点就可以按顺序放在一个hashset中。

第一个点可以通过遍历选择最左下角的那个点。在这里利用向量的点乘来计算cos值,最终转化为目标的极角(或者用math.atan2)。再用迭代器进行迭代即可。

Problem 8: Personal art

这个部分考察自己的想象力,可以充分利用上述实现的方法,主要利用循环等方法设计自己独特的艺术画作。

Submitting

(如何通过Git提交当前版本到GitHub上你的Lab1仓库。)

提交过程比较简单,在项目文件夹中打开Gitbash,输入git push origin master即可。

Social Network

分析问题,要我们构建一个社交网络。

我们可以分两步解决:

  1. 定义Person类

    在这个过程中,主要面对对象设计数据结构和基本方法,比如存储person的name,存储人的朋友的list——FriendshipList;此外例如AddFriend,getName,getFriendshipList等基本方法。

  2. 定义FriendshipGraph类

    在这个类中我们将利用Person类来实现具体功能。

    把问题分解为三个方法来实现,addVertex,addEdge,getDistance。

设计/实现FriendshipGraph类

把问题分解为三个方法来实现,addVertex,addEdge,getDistance。

  1. addVertex

    我们定义List<Person> people =new ArrayList()<>;来存储person的集合,在这里定义一个HashSet,用于除重。

public void addVertex(Person p){
if(nameSet.contains(p.getName())){
System.out.println(“This person has already existed.”);
return;
}
people.add§;
nameSet.add(p.getName());
}

  1. addEdge

    添加边的操作非常的简单,因为在Person类中已经定义了AddFriend,因此只需要1条语句即可:

//注意在这里的未来的数据结构将使用邻接表进行BFS,这里的是无向图的情况,因此要考虑加两条边
p1.AddFriend(p2);

  1. getDistance

    实际上我们此时图的存储结构为一个邻接表,那么我们利用广度优先搜索的策略即可计算最小距离。

public int getDistance(Person p1, Person p2){
if(p1 == p2)
return 0;
Map<Person,Integer> distance = new HashMap<>();//将图抽象为Hashmap
//如果这两个点是连通的,那么通过先广搜索可以确定最短路径。
Queue<Person> queue = new LinkedList<>();
queue.offer(p1);
distance.put(p1, 0);
while(!queue.isEmpty()){
Person t = queue.poll();
List<Person>FriendList = t.getFriendshipList();
for(Person e : FriendList){
if(!distance.containsKey(e)){
queue.offer(e);
distance.put(e, distance.get(t)+1);
if(e==p2) return distance.get(p2);
}
}
}
return -1;//广搜失败,未联通,返回-1;
}

设计/实现Person类

Person类只需要定义name和FriendshipList两个最基本的变量,剩下的是一些基本的方法。

public class Person {
private String name;
private List<Person> FriendshipList;

public Person(String name){
this.name = name;
FriendshipList = new ArrayList<>();
}

public void AddFriend(Person p){
FriendshipList.add§;
}

public String getName(){
return this.name;
}
public List<Person> getFriendshipList(){
return FriendshipList;
}

}

设计/实现客户端代码main()

Main()在实验指导书中已经给出,只需复制并进行测试即可:

1. FriendshipGraph graph = new FriendshipGraph();

2. Person rachel = new Person(“Rachel”);

3. graph.addVertex(rachel);

4. graph.addEdge(rachel, ross);

5. System.out.println(graph.getDistance(rachel, ross));

用户需要首先定义一个FriendshipGraph,在通过Person定义人,通过方法addVertex将其纳入图中,在通过addEdge来描述人与人之间的关系。

在这里插入图片描述

可以看到此时我们的输出与测试样例结果一致。

下面回答实验PPT中的几个问题:

1)如果注释掉第10行的话,新的关系图如下所示:

在这里插入图片描述

Rachel与任何人都不相邻,返回-1;且与自己的距离为0。

经过测试,发现程序的输出与上述猜想一致:

在这里插入图片描述

  1. 如果将第 3 行引号中的“Ross”替换为“Rachel”,你的程序会发生什么?

    下面进行了一下测试,发现我的程序输出仍为1、2、0、-1;

在这里插入图片描述

下面对程序的健壮性进行修改,即用一个HashSet来对上述已经存在的Person类进行查重,一旦发现现在的Graph中已经存在了,将立即报错终止程序,效果如下:
在这里插入图片描述
在这里插入图片描述

可以看到我们的程序正常终止了,程序的健壮性得到了提高。

设计/实现测试用例

给出你的设计和实现思路/过程/结果。

  1. 对addVertix()的测试

在这里插入图片描述

在这里主要是测试加点的功能,第一个测试是否能加入,第二个测试重复的点加入后,是否会输出FALSE而使程序正常终止。

  1. 对addEdge()的测试
    在这里插入图片描述

    主要测试加入边后,原有的person.FriendshipList中是否加入了新的Person,即检验邻接表的正确性。

  2. 对getDistance()的测试

    在这里我构建了一张有环的非连通图,这样各个情况都会被覆盖。

在这里插入图片描述

最终可以看到,我们的程序通过了上述进行的一系列的测试。

实验进度记录

请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。

每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。

不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。

日期时间段任务实际完成情况
2022-04-2712:30-14:30编写问题1的isLegalMagicSquare函数并进行测试按计划完成
2022-04-2814:00-16:30编写了问题2的主体部分遇到困难,未完成,凸包算法未能完成
2022-04-2817:30-18:15编写了问题2的凸包算法按计划完成
2022-04-2818:30-20:00编写了问题3按计划完成
2022-04-3013:00-15:00优化了全部的程序,并编写测试按计划完成

实验过程中遇到的困难与解决途径

遇到的困难解决途径
JDK的版本不符合要求重新下载JDK11 ,发现IDEA可以切换不同版本的JDK,十分的方便。
对于Java的语法掌握的不够熟练,时常想好了做什么,但是找不到合适的对象、方法去实现自己的想法。查阅CSDN和Java官方文档,不断地积累方法,总结编程经验。
对于IDEA的使用不够熟练,文件夹的设置不够熟练上网查阅相关的使用方法,并不断地在编程的过程中使用,使得自己与IDEA磨合的更好

实验过程中收获的经验、教训、感想

实验过程中收获的经验和教训(必答)

在实验的过程中,首先感受到了Java面对对象编程的特点,最大的感受是,一定要清晰地想好如何解决问题,在动手编程,这样通过事先地抽象分析可以使我们的编程逻辑更加简单清晰,节约不少的时间;此外,程序的健壮性十分的重要,一个看似完美的程序实际上存在很多的漏洞,通过Junit单元测试进行“边测试边编程”的方式写出来的程序,往往具备更好的健壮性,而且便于debug查看问题的来源。

最大的教训是对Java的类库等语法的掌握非常不熟练,在实现的过程中因为语法受到了不小的阻力,希望有时间可以熟读Java核心技术,对语法有更加全面的理解。

针对以下方面的感受(必答)

  1. Java编程语言是否对你的口味?与你熟悉的其他编程语言相比,Java有何优势和不足?

    个人比较喜欢Java的风格。

    优点:跨平台、可移植性,安全性,面向对象,简单性,高性能,分布式,多线程,健壮性。

    缺点:运行速度较慢,不能和底层、操作系统等打交道,删除了指针、不够灵活。

  2. 关于Eclipse或IntelliJ IDEA,它们作为IDE的优势和不足;

    我使用的是IDEA,我觉得IDEA的功能比较完善,比如refactor、单元测试等方法是非常便捷的,并且也会提示你是否用Git管理等等;

    缺点是,IDEA 很多强大的功能都是基于其缓存与索引,当打开一个新项目的时候,IDEA 会自动建立索引。这个有时候对大型项目特别不友好,可能会出现卡顿现象。特别对于机械硬盘用户,这种现象会更加明显。

  3. 关于Git和GitHub,是否感受到了它在版本控制方面的价值;

    Git的版本控制使我们的工作更加快捷,比如版本回退、时空穿梭等等;

    GitHub让我们的代码开源,更加便于程序员的开发和对代码的管理。

  4. 关于CMU和MIT的作业,你有何感受;

    更加喜欢MIT的作业,因为他会简单的为学生搭一点框架去逐步的实现功能,完成后比较有成就感。

  5. 关于本实验的工作量、难度、deadline;

    由于初次接触,对Java语言本身的了解不多,导致编程的过程中算法和数据结构的实现受到了阻碍,使原本不多的工作量变得繁杂(因为要去搜索相关的文档),但是好在deadline是比较合理的。

  6. 关于初接触“软件构造”课程;

首先,是对Java语言的使用非常蹩脚;

其次,没有经验,对一些测试方法、框架理解的程度远远不够。

希望能够通过努力深入地学习这门课程。
于其缓存与索引,当打开一个新项目的时候,IDEA 会自动建立索引。这个有时候对大型项目特别不友好,可能会出现卡顿现象。特别对于机械硬盘用户,这种现象会更加明显。

  1. 关于Git和GitHub,是否感受到了它在版本控制方面的价值;

    Git的版本控制使我们的工作更加快捷,比如版本回退、时空穿梭等等;

    GitHub让我们的代码开源,更加便于程序员的开发和对代码的管理。

  2. 关于CMU和MIT的作业,你有何感受;

    更加喜欢MIT的作业,因为他会简单的为学生搭一点框架去逐步的实现功能,完成后比较有成就感。

  3. 关于本实验的工作量、难度、deadline;

    由于初次接触,对Java语言本身的了解不多,导致编程的过程中算法和数据结构的实现受到了阻碍,使原本不多的工作量变得繁杂(因为要去搜索相关的文档),但是好在deadline是比较合理的。

  4. 关于初接触“软件构造”课程;

首先,是对Java语言的使用非常蹩脚;

其次,没有经验,对一些测试方法、框架理解的程度远远不够。

希望能够通过努力深入地学习这门课程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HIT-Steven

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值