软件构造lab1

1 实验目标概述

本次实验通过求解三个问题,训练基本 Java 编程技能,能够利用 Java OO 开 发基本的功能模块,能够阅读理解已有代码框架并根据功能需求补全代码,能够 为所开发的代码编写基本的测试程序并完成测试,初步保证所开发代码的正确性。 另一方面,利用 Git 作为代码配置管理的工具,学会 Git 的基本使用方法
•基本的 Java OO 编程
•基于 Eclipse IDE 进行 Java 编程
•基于 JUnit 的测试
•基于 Git 的代码配置管理

2 实验环境配置

首先,下载jdk8.0版本,eclipse和git。在eclipse中进行java开发,用eclipse自带的junit进行测试,最后用git进行整合提交。
问题和困难:
(1) 困难:按照mit的方法配置eclipse选择advanced mode找不到目标文件。
解决:使用默认安装方式,不选择advanced mode。
(2) 困难:提示A JNI error has occurred, please check your installation and try again,程序无法运行。
解决:发现编译的java版本和项目java版本不一致,均修改为了java SE 1.8就可以了。

3 实验过程

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

3.1 Magic Squares

这个函数要能够从文件中读取矩阵的各个元素,并且判定读入的矩阵是否是符合规范的数据,比如是否以\t分隔各个元素,读入的数据是否是n行n列的矩阵,读入的是否是一个矩阵等等;若读入数据符合规范,则判断是否是magic square,即各行、各列和两个对角线的数据之和是否都相等。

3.1.1 isLegalMagicSquare()

3.1.1.1 思路

这个函数要能够从文件中读取矩阵的各个元素,并且判定读入的矩阵是否是符合规范的数据,比如是否以“\t”分隔各个元素,读入的数据是否是n行n列的矩阵,读入的是否是一个矩阵等等;若读入数据符合规范,则判断是否是magic square,即各行、各列和两个对角线的数据之和是否都相等。

3.1.1.2 过程

(1)首先,采用try catch处理try过程中遇到的IOException。
(2)在try中,利用BufferedReader和readline将文件中的数据逐行读入,边读边计算每行的元素个数(每行的列数),以及每次读入时行数加一(累计读取获得行数),利用string.split()方法,先以小数点‘.’来分隔,以此确定是否存在小数,若存在则return false;若没有,接下来以空格‘ ’来分隔,以此确定是否存在以非“\t”,若存在则return false;若依旧没有,接下来判断该行的元素个数是否与前面各行的元素个数相同,若不同则return false。若以上情况均没有,循环结束后,将列数与行数进行比较,若不同则return false。若行列数也相等,至此确定读入是规范的。
(3)接下来通过循环判断各行、各列和两个对角线的数据之和是否都相等。

3.1.2 generateMagicSquare()

3.1.2.1 生成magic square的方法

(1)由于n是奇数,首先找到矩阵第一行最中间一列,在此处放置1,设i为1,i每次循环加1,接下来函数不断向行减1、列加1(右上角)的位置放置i,若行减1即将小于0了,就换到行号为(n-1)的行(最大行),若列加1即将大于(n-1)了,就换到列号为0的列(最小列)。
(2)遇到右上角元素已经被放置的情况(每当i不为0且i是n的倍数时),行号加1,列保持不变。因此,对于这n次处理n个连续的数,每行、列、负对角线都恰好有一个某次处理中按数值大小排行第i的数(i=1,2,…,n),且n次处理中,对于同一个行、列或负对角线,i的值各不相同,(如,n=3时,第一行:有第一次连续的3个数(1,2,3)当中数值排行第3的1,有第二次连续的3个数(4,5,6)当中数值排行第1的6,有第三次连续的3个数(7,8,9)当中数值排行第2的8),而矩阵的每个子阵的正对角线上,恰好为i相同的数,且magic square的正对角线上的i为n/2。因此矩阵满足各行、列、对角线自身的和相等。由于n是奇数,恰好能以此方法填满矩阵。
如:n=3时,生成的magic square,及每个数字对应每次处理中的数值大小排序(i)的值如下

图

3.1.2.3 中文注释

public static boolean generateMagicSquare(int n) {
int magic[][] = new int[n][n];//为生成n*n的矩阵各数值分配空间
int row = 0, col = n / 2, i, j, square = n * n;//首先定位到第一行最中间列处放置1
for (i = 1; i <= square; i++) {
magic[row][col] = i;
if (i % n == 0)//若i是n的倍数,则代表本次连续的n个数处理完毕
row++;//增加行以处理下一次连续的n个数
//对于这n次处理n个连续的数,每行、列、负对角线都恰好有一个某次处理中按数值大小排行第i的数(i=1,2,…,n),且n次处理中,对于同一个行、列或负对角线,i的值各不相同
else {//函数不断向行减1、列加1(右上角)的位置放置比当前数值大1的数
if (row == 0)//若行减1即将小于0了,就换到行号为(n-1)的行(最大行)
row = n - 1;
else//行-1
row–;
if (col == (n - 1))//若列加1即将大于(n-1)了,就换到列号为0的列(最小列)
col = 0;
else//列+1
col++;
}
}
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
System.out.print(magic[i][j] + “\t”); //以"\t"为同一行各数之间的分隔符,打印矩阵
System.out.println();
}
return true;
}

3.1.2.4 n为偶数或n为负数产生异常的原因

(1)n为偶数时,发生ArrayIndexOutOfBoundsException,意味着数组越界。在n为偶数时,由于最开始无法将1放置在矩阵第一行最中间,在第(n/2+1)次处理n个连续数字时,会执行row++,然而此时的行数已经是n-1了,因此row变成n,而数组中row最大为n-1,就发生了数组越界。
如,n=4时,第3次处理4个连续数字时情况如下图所示(9是第3次处理的第一个数字,它的行号为4,超过了最大行号3,发生了数组越界)

(2)n为负数时,发生NegativeArraySizeException,意味着试图将数组大小设置为负数。这个异常在int magic[][] = new int[n][n];语句处就发生了,因为数组大小不能为负。

3.1.2.5 作扩展后的函数

首先,使用BufferedWriter和FileWriter来进行文件写操作

接下来,使用try catch来处理可能出现的ArrayIndexOutOfBoundsException、NegativeArraySizeException和IOException(写操作可能会抛出的异常),使他们都打印提示信息并return false以做到优雅退出。

接下来,尝试生成n为5的magic square并用isLegalMagicSquare进行测试,得到结果为true。

3.2 Turtle Graphics

本任务操作turtle进行画图,并训练用git提交实验到github的能力。同时,训练有关角度、长度的图形算法(凸包算法,计算向量旋转角度等)。

3.2.1 Problem 1: Clone and import

首先,按照要求新建Lab1-学号文件夹,在git bash中进入该文件夹的目录下,即在命令行中输入:
cd /e/2021SC/lab1/Lab1-学号
在命令行中输入git init来创建空仓库。
将P2代码从https://github.com/rainywang/Spring2020_HITCS_SC_Lab1/tree/master/P2中克隆下来。由于git clone命令始终遇到fatal: unable to access ‘https://github.com/rainywang/Spring2020_HITCS_SC_Lab1/tree/master/P2/’: Failed to connect to github.com port 443: Timed out,因此直接进入github网站下载zip压缩包,手动将P1,P2文件夹复制到指定位置。
使用git add filename命令将需要的文件来进行追踪,全部配置好之后用git commit -m “commit message”命令将工作区域的文件全部提交到仓库中。

3.2.2 Problem 3: Turtle graphics and drawSquare

思路是,正方形的生成是每次顺时针旋转90°,然后走一个sideLength。已知边长sideLength,则分4次走,每次顺时针转90°、走sideLength个像素点。代码如下:

3.2.3 Problem 5: Drawing polygons

3.2.3.1 calculateRegularPolygonAngle

思路:正n多边形的内角大小为(n-2)*180°/n,因此代码如下:

运行TurtleSoupTest.java,得到junit测试结果如下:

把函数改错之后,得到junit测试结果如下

然后又重新改回正确的了。

3.2.3.2 drawRegularPolygon

正多边形最底下的边都是水平的,因此考虑先顺时针转90°,然后对于由sides条边的正多边形的绘制,调用calculateRegularPolygonAngle()函数,每次顺时针转的角度大小为180 calculateRegularPolygonAngle(sides),重复走sides次即可,故有代码如下

测试绘制一个正三角形,输出如下图所示

3.2.4 Problem 6: Calculating Bearings

3.2.4.1 calculateBearingToPoint

假设currentBearing = 0时从当前点到目标点的需要顺时针旋转的角度为angles。
若angles>=currentBearing,则需要旋转的角度恰为angles – currentBearing;
若angles<currentBearing,则需要旋转的角度恰为360 + angles – currentBearing;
分类讨论计算出angles的值,然后作如上关于angles和currentBearing的大小比较,就能确定函数的返回值。因此有代码如下:

3.2.4.2 calculateBearings

从xCoords和yCoords中遍历获得每个坐标,调用calculateBearingToPoint函数求出每次的角度,加入到List中,最后return。

3.2.5 Problem 7: Convex Hulls

运用凸包算法进行求解。
首先找到纵坐标最小的点。
然后将其他点按照该点与其连成的向量(纵坐标最小的点指向它)与x轴正方向夹角按照从小到大进行排序(利用余弦值进行排序,我用的是冒泡排序算法)。
接下来,
我写了三个辅助函数,分别是

  1. public static double pointCos(double x, double y) {
    return (x/Math.sqrt(xx + yy));
    }
    该函数计算余弦值。
    2.public static int isCounterClockWise(Point a, Point b,Point c)
    用于判断当前需要进行判断是否压栈的点,栈顶两个点与该点三点向量是否是逆时针转动,若是,则将该点压入栈中,否则若是顺时针将栈顶元素弹出,若在同一条边上,则判断该点是否在栈顶两个点连成的线段上,若是则直接处理下一个点,若不是则将栈顶的点弹出,将该点压栈。
  2. public static double calculateBearingToPointDouble(double currentBearing, double currentX, double currentY, double targetX, double targetY)
    因为calculateBearingToPoint函数的坐标值是int类型,而point类的坐标是double类型,我又写了一个相同功能的函数(用于计算旋转角度)。

3.2.6 Problem 8: Personal art

画了一个万花筒
万花筒

3.2.7 Submitting

如何通过Git提交当前版本到GitHub上你的Lab1仓库。
首先,用git init在Lab1-1180100406文件夹的路径下新建空仓库,然后用git add将需要的目录、文件等从工作区添加到暂存区,然后用git commit将暂存区的文件提交到本地仓库,将远程仓库连接存为快捷写法origin,最后用git push origin master将本地仓库推到远程仓库(origin地址处)的master分支下。比如以下是我最新一次提交时所做的操作。

3.3 Social Network

构建表示人际关系的无向图,能计算任意两个人之间的最短距离。然而所有函数实现等要做到随时能够将该类扩展到有向图上。

3.3.1 设计/实现FriendshipGraph类

1.首先,创建顶点集数组、邻接矩阵表头数组。由于不知道顶点数目,定义变长数组list。
其中,邻接矩阵表头数组的定义如下,由于list.get()函数能顺序访问数组,每个顶点按照序号有与之一一对应的邻接矩阵表头数组元素,将它指向的所有顶点加入nextv数组,就构成了邻接表。
public class Vhead{
public List nextv = new ArrayList();
}
public List vhead = new ArrayList();

2.这个类包含三个函数:
(1)public boolean addVertex(Person tmpname)
该函数实现将创建的person对象加入顶点集和邻接矩阵表头数组(使用list.add()),并同时将顶点集数目++,若出现与顶点集中某个顶点name相同的情况,打印错误信息并exit。
(2)public void addEdge(Person v1, Person v2)
该函数将v2加入v1对应的邻接矩阵表头数组元素的nextv(v1指向的顶点集),这是为了未来将该类扩展为有向图作准备。
(3)public int getDistance(Person v1, Person v2)
该函数计算从v1到v2的最短距离,由于每对邻接的顶点之间距离均为1,不需要使用Dijkstra算法,只需要使用广度搜索即可,使用mark[]进行标记,使用队列Queue进行实现,每一层广度搜索让距离distance++,找到后return distance。若未搜索到,则表示两个顶点不邻接,return -1。

3.3.2 设计/实现Person类

首先需要有name,是唯一对应的标识符,不能出现两个对象名字一样。有传输入string时构造新的对象(以string内容为name)的构造函数,同时为了便于实现邻接表,采用序号,每个person类的对象按照创造时间先后序号从小到大排列。

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

设计了一个standard out用于表示函数没有中途因为异常或错误操作而退出,我的main打印一句话,代码如下
System.out.println(“Perfectly performed”);
因为比如说若出现重复使用同一个name的情况会直接退出程序,若输出了"Perfectly performed"则代表函数没有出现这种错误。

3.3.4 设计/实现测试用例

使用junit进行测试
1.使用assertequals函数来判断getDistance的值是否符合预期。同时,加入如下test来测试能否正常运行测试。
@Test(expected = AssertionError.class)
public void testAssertionsEnabled() {
assert false;
}
我测试了距离为0、1、2、3和顶点不邻接的情况,由于我的函数分4个阶段求distance,第一阶段是判断距离是否为0,第二阶段构建初始队列(距离为1),第三阶段为广度搜索的第一步(将初始队列中的顶点邻接的顶点全部push进队列,此时距离为2),第四阶段是重复第三阶段中的操作(距离≥3)。最后,若在广度搜索中未找到顶点,则return -1。
2.构建自定义异常UsedNameException,一旦在addVertex时读到相同name,抛出该异常,在catch中的处理方式是return false。若没读到,return true。

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

遇到的难点解决途径
一开始未学习过java,对java的语法不熟悉。遇到需要实现的功能,在csdn中进行检索相关方法,并对照java书籍进行深入学习。
不知道怎样将.txt格式的文件导入java的src目录下的P1文件夹。通过不断尝试,发现直接在本地将文件复制进eclipse-workspace文件夹下的对应文件夹中即可。
git clone命令无法正常运行,总是遇到fatal: unable to access ‘https://github.com/rainywang/Spring2020_HITCS_SC_Lab1/tree/master/P2/’: Failed to connect to github.com port 443: Timed out直接进入github网站下载zip压缩包,手动将P1,P2文件夹复制到指定位置
git diff命令没有输出查阅git diff的原理,发现我在写完代码之后才将P2 add进了暂存区,因此和add之前没有变化,应该在修改之前就add
git commit显示no write since last change不让退出vim查阅git commit的相关命令,使用:q!不保存退出,之后再次修改,使用:wq保存退出
基于SSM框架的智能家政保洁预约系统,是一个旨在提高家政保洁服务预约效率和管理水平的平台。该系统通过集成现代信息技术,为家政公司、家政服务人员和消费者提供了一个便捷的在线预约和管理系统。 系统的主要功能包括: 1. **用户管理**:允许消费者注册、登录,并管理他们的个人资料和预约历史。 2. **家政人员管理**:家政服务人员可以注册并更新自己的个人信息、服务类别和服务时间。 3. **服务预约**:消费者可以浏览不同的家政服务选项,选择合适的服务人员,并在线预约服务。 4. **订单管理**:系统支持订单的创建、跟踪和管理,包括订单的确认、完成和评价。 5. **评价系统**:消费者可以在家政服务完成后对服务进行评价,帮助提高服务质量和透明度。 6. **后台管理**:管理员可以管理用户、家政人员信息、服务类别、预约订单以及处理用户反馈。 系统采用Java语言开发,使用MySQL数据库进行数据存储,通过B/S架构实现用户与服务的在线交互。系统设计考虑了不同用户角色的需求,包括管理员、家政服务人员和普通用户,每个角色都有相应的权限和功能。此外,系统还采用了软件组件化、精化体系结构、分离逻辑和数据等方法,以便于未来的系统升级和维护。 智能家政保洁预约系统通过提供一个集中的平台,不仅方便了消费者的预约和管理,也为家政服务人员提供了一个展示和推广自己服务的机会。同时,系统的后台管理功能为家政公司提供了强大的数据支持和决策辅助,有助于提高服务质量和管理效率。该系统的设计与实现,标志着家政保洁服务向现代化和网络化的转型,为管理决策和控制提供保障,是行业发展中的重要里程碑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值