软件构造Lab1总结

2020年春季学期

计算机学院《软件构造》课程

2 实验环境配置

Eclipse,JDK8,Git,Junit4

在假期未开课刚学习Java语言下载JDK时,网速特别慢,凌晨下载时速度稍有提升,才下载成功。又经过网上查询环境变量配置的方法,由于忽略了一些东西,而且电脑中又有老师发送的JDK8和自己下载的JDK13,尝试了几次之后环境变量配置成功。

3 实验过程

3.1 Magic Squares

任务理解:编写isLegalMagicSquare()函数,使用文件名为参数判断是否为幻方。将generateMagicSquare产生的magic square写入文件\src\P1\txt\6.txt中;并调用isLegalMagicSquare()函数验证生成的矩阵是否为幻方。

3.1.1 isLegalMagicSquare()

首先通过查阅资料找到合适的读取文件的方式,读取作为参数的文件名。按行读取矩阵。

使用HashMap<Integer, String[]> words = new HashMap<Integer,String[]>();

创建散列表,将int row与字符串组成的数组对应起来;

String[] word = line.split("\t");// word[]是一行的所有数组成的字符串数组

以‘\t’分割矩阵的一行,将一行的n个数放置到有n个字符串的 word数组中;

然后通过查阅资料使用遍历字符串的方法判断是否有除‘-’ ‘.’以外的非法字符,判断是否各行的数组长度相等,若不相等则输出不是矩阵。然后判断行列数是否相等,列数即为每行数组的长度,行数在分割矩阵的时候已进行计算。

int num = Integer.valueOf(words.get(j)[i]);// 把字符串强制转换为数字

将word数组中每一个字符串元素强制转换成数字,判断num是否大于0,且为整数。

int[] row_sum = new int[row];

int[] col_sum = new int[col];

int[] dia_sum = new int[2];

定义三个数组存放行,列,对角线的和,在求出每一行的和就与第一行的和进行比较,求出每一列的和就与第一列的和进行比较

以下为求正对角线之和,相邻两个对角线数的位置关系是横纵坐标均加一,求反对角线也类似

for (i = 0; i < row; i++, j++)

dia_sum[0] = dia_sum[0] + Integer.valueOf(words.get(i)[j]);

比较dia_sum[1]和dia_sum[0],最后最后比较row_sum[0],col_sum[0],dia_sum[0];

在上述计算比较之后若函数没有返回false,则说明该矩阵就是幻方。

3.1.2 generateMagicSquare()

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

public static boolean generateMagicSquare(int n) throws IOException {

    if(n<=0)//n为负数,输出信息,退出

     {

     System.out.println("输入的n为负数,不符合要求!");

     System.exit(1);

     }

     

    if(n%2==0)//n为偶数,输出信息,退出

     {System.out.println("输入的n为偶数,不符合要求!");

     System.exit(1);

     }

    int magic[][] = new int[n][n];

    int row = 0, col = n / 2, i, j, square = n * n;



    for (i = 1; i <= square; i++) {

       magic[row][col] = i;//赋值一个矩阵元素

       if (i % n == 0)//下一个位置是已经被赋值过的,不能重复赋值

           row++;//所以要开始赋值下一个斜道

       else {

           if (row == 0)//元素赋值到了第一行,

               row = n - 1;//下一次赋值转到最后一行

           else

               row--;//否则行数减1

           if (col == (n - 1))//假如元素赋值到最后一列,

               col = 0;//下一次赋值转到第一列

           else

               col++;//否则列数加1

       }

    }

    File f=new File("src/P1/txt/6.txt");

    Writer print=new FileWriter(f);//第二个参数为空,所以每次写入文件时清空原有内容

    for (i = 0; i < n; i++) {//输出矩阵

       for (j = 0; j < n; j++)

           {System.out.print(magic[i][j] + "\t");

           print.write(magic[i][j]+"\t");

           }

       System.out.println();

       print.write("\n");

    }

   print.close();

    return true;

}

3.2 Turtle
Graphics

补全函数满足要求的功能,练习List,Set等结构,初步接触Junit测试.

3.2.1 Problem 1: Clone and import

https://github.com/rainywang/Spring2020_HITCS_SC_Lab1/tree/master/P2来fork代码到自己的github账号中,然后在自己的账号中clone代码,在浏览器中下载代码。打开Git Bash,通过网络查找命令行git init使用方式来将自己本地的一个文件夹作为本地库,通过git remote add origin https://github.com/ComputerScienceHIT/Lab1-1180300412.git命令来将本地库与远程库进行关联。

3.2.2 Problem 3: Turtle graphics and drawSquare

画正方向四个循环将四个边画出来,每次循环执行turtle.forward(sideLength);

 turtle.turn(90);

3.2.3 Problem 5: Drawing polygons

通过多边形的内角公式,double angle=(double)(sides-2)*180/sides;计算出多边形的内角大小,画多边形使用180-之前算出的内角大小就得到海龟需要拐的角度了。

还有根据内角大小返回边数的函数实现,根据公式也能得到,但是由于内角大小是double,而边数是int,所以数据将会有舍入(例如6.998强制类型转换会返回6),在Junit测试时会有不通过,使用以下代码处理

double sides= (double)360.0/(180-angle);//由内角和公式得到

 if(sides-(int)sides>=0.999)//防止6.9998这种类型被强制转换成6

    return (int)sides+1;

 return (int)sides;

3.2.4 Problem 6: Calculating Bearings

通过查找资料找到Java中的库函数Math.atan2,计算两点连线与x轴正方向的夹角的弧度值

double angle=Math.atan2(targetY-currentY, targetX-currentX);//两点连线与X轴正方向的夹角弧度值

 angle=90-Math.toDegrees(angle)-currentBearing;//两点连线与Y轴的夹角再减去初始的方向角度

其次使用Math.toDegrees来将弧度值转换为角度值

对于输入x,y值的列表的,初始的角度angle设置为0,然后通过前两个点求出返回列表的第一个元素,然后使用atan2函数就可以求出从第二个点到第三个点时的初始朝向角度,循环执行就得到结果了。

Bearings.add(calculateBearingToPoint(angle,xCoords.get(i),yCoords.get(i),xCoords.get(i+1),yCoords.get(i+1)));

    angle=Math.toDegrees(Math.atan2(yCoords.get(i+1)-yCoords.get(i), xCoords.get(i+1)-xCoords.get(i)));

    i++;

3.2.5 Problem 7: Convex Hulls

凸包算法,可以求出纵坐标最小的点,该点一定在凸包上,然后根据以该点为原点,连接其余点,求出极角最小的点,将上述两点加入到凸点集中,然后以第二个点为原点重复操作,然而以上述思路中,我编写的凸包代码没能全部通过测试

3.2.6 Problem 8: Personal art

通过switch(i%8)语句在每次画完一个多边形后能够改变一种颜色,通过for循环,每次画出的多边形边长增加4个单位,得到蜗壳形状。

在这里插入图片描述

3.2.7 Submitting

通过git status 语句来查看文件的变化情况,然后使用git add *.*语句将文件添加,使用git commit语句提交,最后使用git push origin master来推送修改后的文件到远程库。完成上述操作后,可以登录github账号查看到刚刚推送过去的新版本。

3.3 Social Network

对有向图进行操作,添加点和边,查找给定的两点之间的最短距离。另外添加防止重名的功能。练习编写Junit测试用例,对代码进行测试。

3.3.1 设计/实现FriendshipGraph类

使用一个字符串的列表来存储所有人的名字,在使用addVertex时就可以通过names来看是否已经存在这个名字;然后使用散列表来将每个人来和他的朋友列表对应起来。

List names=new ArrayList();//姓名列表,增加名字时防止重名,且可以得到当前的人数

HashMap<Person,LinkedList>
people=new
HashMap<Person,LinkedList>();//每个人对应了他的朋友列表

addVertex函数:使用if(names.contains(person.getname()))来判断加入的这个人的名字是否已经有人用了,假如这个名字在名单names中不存在,那么创建一个朋友列表存储加入元素person的朋友,将person加入到他自己的朋友列表中,然后将person的名字加入到names中,然后将person和他的朋友列表put进people散列表中

LinkedList a=new LinkedList();

    a.add(person);

    names.add(person.getname());

    people.put(person,a);

addEdge函数:if(names.contains(a.getname())&&names.contains(b.getname()))

                 people.get(a).add(b);

   检查加入的两个人的名字是不是存在,假如存在的话在a的朋友列表中加入b。

getDistance:Queue queue=new LinkedList();

    HashMap<Person,Integer> distance=new HashMap<Person,Integer>();//每个人离a的距离

  创建队列和散列表,散列表将每个人与他和原点的距离对应起来

 使用广度优先搜索,从原点开始进行搜索,对所有的点像层序遍历一样,第二层的点是第一层的点的朋友,到原点距离为distance.get(原点)+1;,然后将第二层的点入队,将第二层的点和他们距原点的距离置入到散列表distance中。然后将队头出队,遍历其朋友,这时已经是第三层了,第三层的点到原点距离为第二层的距离加一,重复上述操作,在遍历时检查点是否是已经遍历过的点(在distance散列表中能够查找到对应键)如果是已经检查过的点,则开始下一个点;以及检查点是不是终点,如果是的话,返回该层与原点的距离。当弹出的队头的朋友遍历完之后,再弹出一个队头元素,对其朋友列表同样进行遍历。重复操作,直到队列为空或函数已经返回。

如果上述操作全部完成,则说明终点与原点不连通,返回-1.

在这里插入图片描述

第二层的点和第一层的原点距离为0+1,第三层的点和第一层的距离(0+1)+1,第四层的点和第一层距离为[(0+1)+1]+1一直递推就可以求出图中任意一个元素和原点的距离。

3.3.2 设计/实现Person类

private
String name;

public Person(String name)

{

    this.name=name;

}

public String getname()

{

    return name;

}

老师提示在起名字的时候不会知道是否重名,只有在加入到graph.names中时才能知道,所以在person中不设置判断重名的语句。

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

设置十个点,加入边,其中有些点之间有不止一条路,第十个点设置为与其他点不连通。分别输出连通点之间的距离,不连通点之间的距离,中间有不同长度的路的两点间的距离

3.3.4 设计/实现测试用例

addVertexTest: Person a 在执行addVertex之前,在names中判断是否有a.getname();调用addVertex同时捕捉异常,如果出现异常则assertEquals(true,false);构造一个错误出来。然后再在names里面查看是否有a的名字, assertEquals(true,graph.names.contains(a.getname()));重名检测使用Junit测试有困难,在调试时设置过两个同名的人,能够识别出来并退出程序。

addEdgeTest:

在未进行addEdge操作前查看a的朋友列表是否含有b,b的朋友列表是否有a,正确结果是都没有。assertEquals(false,graph.people.get(a).contains(b));

           assertEquals(false,graph.people.get(b).contains(a));

然后进行 graph.addEdge(a,b);

assertEquals(true,graph.people.get(a).contains(b));

    assertEquals(false,graph.people.get(b).contains(a));

再执行graph.addEdge(b,a);,此时b的朋友列表中应该有a了。

  assertEquals(true,graph.people.get(b).contains(a));

getDistanceTest:定义了十个人,其中a10与其他点没有连通,其余有些点之间有不止一条路连接,且路的长度不同。

assertEquals(0,graph.getDistance(a1, a1));//自己和自己距离为0

     assertEquals(3,graph.getDistance(a1, a8));

     assertEquals(3,graph. getDistance(a6, a7));

     assertEquals(2,graph.getDistance(a7, a4));

   assertEquals(-1,graph.getDistance(a3, a10));//a10与a3不连通
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值