目录
实验环境配置
阅读eclemma官网的安装配置方法,将install按键拖到eclipse的workspace,然后在打开的eclipse marketplace中点击install即可。
在eclipse的workspace中新建java project,其中每一个目录中的文件夹都是source folder(之前不太了解eclipse时使用过folder,发现没有对应功能,必须使用source folder),从github获取代码框架,按照实验手册要求的目录结构完成目录构建。
在我的电脑文件夹中进入eclipse的workspace,在本次实验的project文件夹中右击选择git bash here,在git窗口中完成新建、配置仓库(git init新建仓库)。
实验过程
Poetic Walks
Get the code and prepare Git repository
由于网络问题,使用git clone命令持续报错,我采用了在github直接download压缩包,解压缩后将代码的工程文件夹放入指定目录下的方式获取任务代码。
创建java project,命名为Lab2-学号,在eclipse中配置目录达成实验手册要求。在eclipse的workspace文件夹中,进入Lab2-学号工程文件夹,右键选择GIT Bash here,在GIT Bash中使用git init命令创建空仓库,使用git add将需要的文件夹加入暂存区,使用git commit –m “…”命令来将暂存区的文件进行提交到本地仓库(按照实验手册要求进行分次commit和push),然后使用git remote add origin (我的github仓库地址)配置远程仓库的名称,通过git push origin master来将本地仓库的内容push到远程仓库的master分支上。
Problem 1: Test Graph String
这个问题要求有高覆盖度的Testing strategy。需要经过分析,加上eclemma的数据分析。
Problem 2: Implement Graph
这个问题要求写完两个图(一个用边存储图,一个用顶点存储图),同时完成它们俩的测试用例书写,要借助分析+eclemma工具来尽可能达到高的覆盖度。
Implement ConcreteEdgesGraph
ConcreteEdgesGraph的完善
因为要以边为单位存储图,且要求存储边的自定义类Edge是immutable的,因此将fields都设置成private且final的。当某个边发生修改时,直接删除这个实例,创建新的实例加入边集。
完善了checkRep()函数的书写。
完善了toString()的覆写和spec,打印这个图的顶点数目、所有顶点label、边的数目、所有边的信息(这条边的发出顶点、指向顶点和权值)。
其他函数都按照Graph<L>中的spec来书写即可。
对于自定义类Edge,写了三个函数分别获得这条边的发出顶点、指向顶点和权值。
完善了自定义类Edge的checkRep()函数的书写。在这个class中,只要保证所有存储的边的权值都大于0即可。
完善了自定义类Edge的toString()的覆写和spec,打印这条边的发出顶点、指向顶点和权值。
ConcreteEdgesGraph的测试用例书写
除了GraphInstanceTest之外,还要测试ConcreteEdgesGraph的toString()函数、自定义的Edge类。
Implement ConcreteVerticesGraph
ConcreteVerticesGraph的完善
因为要以顶点为单位存储图,且要求存储边的自定义类Vertex是mutable的,因此将fields都设置成private即可,而不要final(但顶点的label要用final,防止被修改成与其他顶点label相同的情况)。当某个边发生修改时,修改相关的顶点实例信息(修改邻接表)。
完善了checkRep()函数的书写。
完善了toString()的覆写和spec,打印这个图的顶点数目、所有顶点label、边的数目、所有边的信息(这条边的发出顶点、指向顶点和权值)。
其他函数都按照Graph<L>中的spec来书写即可。
对于自定义类Vertex,用一个Map<Vertex, Integer>类型的nextv表示邻接表(表示从这个顶点出发的所有边,存储每个边的指向顶点和权值)。用getNextVertex()函数获取上述邻接表(使用了defensive copy,虽然类型是mutable的,还是使用规定函数来进行修改比较好)。又写了三个函数分别添加、修改、删除邻接表中的一条边。用getLabel()函数获得顶点的label。
完善了自定义类Vertex的checkRep()函数的书写。在这个class中,只要保证所有存储的边的权值都大于0即可。
完善了自定义类Vertex的toString()的覆写和spec,打印这个顶点的label和邻接表边数、每条边的信息(条边的发出顶点、指向顶点和权值)。
ConcreteVerticesGraph的测试用例书写
除了GraphInstanceTest之外,还要测试ConcreteVerticesGraph的toString()函数、自定义的Vertex类。
Problem 3: Implement generic Graph
Make the implementations generic
将String改成L,将类名后面加上<L>。
Implement Graph.empty()
用ConcreteEdgesGraph实例化一个空图然后return。
在GraphStaticTest.java中我添加了Integer和Double类型的图的test。
Problem 4: Poetic walks
使用上面任务所做的图来完成语料库图的构建。这个任务中,要对于输入的语句进行处理,根据空格将字符串分成字符串数组,若两个连续的字符串数组元素tmpname1和tmpname2在语料库图中有对应的路径,且该路径长度为2(中间经过另一个顶点(称为bridge word)),则在这两个字符串元素之间加上该bridge word。当然,如果有多条满足上述条件的路径,选择权值最大的边的bridge word加入。
Test GraphPoet
GraphPoet的String类型构造函数书写
新增构造函数,让GraphPoet能除了使用file,还能直接被输入的String构造出来。
GraphPoetTest的测试用例书写
将语料库放在test/P1/poet/路径下。
Implement GraphPoet
使用BufferReader、FileReader和readLine函数打开、阅读corpus,同时将读进来的语料库用toLowerCase函数转换成小写字母(题目要求对大小写不敏感),利用Graph类的方法,遍历corpus,构建一张语料库图。因为使用的是ConcreteEdgesGraph来表示语料库图,若预备加入的边的两个顶点都存在,再考虑这条边是否存在(因为若没点,必然没边),若边存在则将原边删除、权值加一之后重新加入边。
checkRep函数检查边的权值大于0、没有两条边的发出顶点和指向顶点都一样。
Poem函数把输入的字符串用空格分隔开成为一个字符串数组,然后查找语料库图,若两个连续的字符串数组元素tmpname1和tmpname2在语料库图中有对应的路径,且该路径长度为2(中间经过另一个顶点(称为bridge word)),则在这两个字符串元素之间加上该bridge word。当然,如果有多条满足上述条件的路径,选择权值最大的边的bridge word加入。
Graph poetry slam
对于语料库mugar-omni-theater.txt,输入"Test the system.",输出如下图:
使用Eclemma检查测试的代码覆盖度
对于Main,无法进行测试。
Before you’re done
先使用git add将需要的目录、文件等从工作区添加到暂存区,然后用git commit –m (注释)将暂存区的文件提交到本地仓库,用git remote add将远程仓库链接存为快捷写法origin,最后用git push origin master将本地仓库推到远程仓库(origin地址处)的master分支下。
Re-implement the Social Network in Lab1
利用p1中完成的Graph类构建表示人际关系的图,每个顶点表示一个人,每条边的权值为1,能添加人、任意两人的人际关系,能计算任意两个人之间的最短距离。
FriendshipGraph类
Fields
用ConcreteEdgesGraph来创建一个空的人际关系图。
方法
该类有5个方法:
构造函数FriendshipGraph()
创建一个空的人际关系图。
addVertex()
将label是tmpname的点加入图的点集。
addEdge()
将label是v1和label是v2的两个点之间的边加入图里。
getDistance()
获得label是v1和label是v2的两个点之间最短路径长度。
main()
main打印一句话来standard out,我选择的是"Perfectly performed",与lab1中一致。
Person类
Fields
用一个字符串来表示label(即人名)。
用一个int类型的marknum来辅助getDistance函数(因为无向图需要用编号辅助进行广度搜索)。
方法
该类有3个方法:
构造函数Person()
创建一个空的人。
getLabel()
获得这个人的label。
覆写equals()
因为ConcreteEdgesGraph中的add方法需要调用equals判断是否相等,就需要给这个类覆写equals。
覆写hashCode()
因为覆写了equals,所以要配套书写hashCode。因为equals判断相等的依据是label相等,因此使用label的hashCode来表示Person类的hashCode即可。
客户端main()
main打印一句话来standard out,我选择的是"Perfectly performed",与lab1中一致。
提交至Git仓库
先使用git add将需要的目录、文件等从工作区添加到暂存区,然后用git commit –m (注释)将暂存区的文件提交到本地仓库,用git remote add将远程仓库链接存为快捷写法origin,最后用git push origin master将本地仓库推到远程仓库(origin地址处)的master分支下。
实验过程中遇到的困难与解决途径
遇到的难点 | 解决途径 |
---|---|
Eclipse报错:The project was not built since its build path is incomplete. Cannot find the class file | 发现之前一开始下载错了jdk版本,下了jdk15,后来虽然重安了jdk8,但jre还是15,因此重新下载了jre8,重新配置eclipse的jre就解决了。 |
Eclipse报错:Project ‘项目名’ is missing required source folder: ‘文件名’ | 发现配置目录之前书写的代码,让java project生成了对配置目录前有效的build path,将错误的build path remove即可。 |
toString输出不符合预期,比预期的字符串开头多了null | 用于连接(使用+连接)的初始字符串不能初始化为null,而是初始化为" "。 |