2022年春季学期
计算学部《软件构造》课程
Lab 2实验报告
3.1.1 Get the code and prepare Git repository
3.1.2 Problem 1: Test Graph <String>
3.1.3 Problem 2: Implement Graph <String>
3.1.3.1 Implement ConcreteEdgesGraph
3.1.3.2 Implement ConcreteVerticesGraph
3.1.4 Problem 3: Implement generic Graph<L>
3.1.4.1 Make the implementations generic
3.1.4.2 Implement Graph.empty()
本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象 编程(OOP)技术实现 ADT。具体来说:
⚫ 针对给定的应用问题,从问题描述中识别所需的 ADT;
⚫ 设计 ADT 规约(pre-condition、post-condition)并评估规约的质量;
⚫ 根据 ADT 的规约设计测试用例;
⚫ ADT 的泛型化;
⚫ 根据规约设计 ADT 的多种不同的实现;针对每种实现,设计其表示 (representation)、表示不变性(rep invariant)、抽象过程(abstraction function)
⚫ 使用 OOP 实现 ADT,并判定表示不变性是否违反、各实现是否存在表 示泄露(rep exposure);
⚫ 测试 ADT 的实现并评估测试的覆盖度;
⚫ 使用 ADT 及其实现,为应用问题开发程序;
⚫ 在测试代码中,能够写出 testing strategy 并据此设计测试用例。
IDEA自带覆盖率测试的插件,所以不用下载
GitHub Lab2仓库的URL地址:
git@github.com:ComputerScienceHIT/HIT-Lab2-120L020927.git
请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
- 首先实现Graph<String>的实现,再扩展到泛型
- 利用实现的Graph类,应用图的思想,实现GraphPoet类,如果输入的文本的两个单词之间存在桥接词,则插入该桥接词;若存在多个单一桥接词,则选取边权重较大者。
Git命令:
git init
git remote add origin https://github.com/rainywang/Spring2022_HITCS_SC_Lab2/tree/master/P1git pull origin master
git add .
git commit -m “init”
git push origin master
根据规约内容和返回值,按照等价类的划分来测试不同的函数
- add:分别选择在点集中的点和不在的点进行测试
- Set:对set方法进行测试,等价类划分:设置的边已经在图中,权值依次为大于零(即需要更新权值)、等于零(即删除该边)、小于零(是非法情况,不做任何操作);设置的边不在图中,但顶点在图中,权值依次为大于零、等于零、小于零;设置的边的顶点不在图中,权值依次为大于零、等于零、小于零。
且要判断SET之后的图是否为所期望的图
- remove:划分为删除的点在点集合中,不在点集中,且最后要测试修改后的图是否为所期望
- Vertices:加入你的点,测试是否都在点集中
- Sources:创建自己的图,来判断返回的是否与创建的图相同
- Targets:创建自己的图,来判断返回的是否与创建的图相同(与上一个相似)
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
- 设计edge即边类,首先需要rep是权重weight,以及起点(source)和终点(target)
- 设计边类checkRep:首先不能存在重复的点,且权值为正整数
- 写equal()方法和toString(),发现系统自动生成的就可以用
- 针对所有的rep写get方法
- 用写好的edge来编写ConcreteEdgesGraph,用表格形式展示
方法名称 | 实现 |
Add | 检查点集中是否已经存在,如果不存在则添加返回true,如果存在则返回false |
Set | 先检查set的边是否已经在边集里存在,如果不存在那么直接在函数开始就加上该边返回0。如果不是,那么开始判断权值是否大于0, 大于0 的话则把权值改为现在的输入的权值,返回上一次权值;等于0则删除这条边,返回上一次权值。如果是第一次创建边那么返回0 |
Remove | 如果删除边在点集中那么首先删除该点,再遍历所有边,凡是用该点作为起点或终点的边全部删除,然后返回true,否则返回false |
Vertices | 返回vertices表即可 |
Sources | 遍历所有的边,如果某条边的终点是输入参数,就将其放进结果映射中,最后返回结果映射 |
Targets | 遍历所有的边,如果某条边的起点是输入参数,就将其放进结果映射中,最后返回结果映射。 |
ToString | 依次遍历点集vertices和边集edges,将所有信息组合成字符串,格式为”Vertices:…,Edges:…” |
- 设计实现vertices类,rep需要一个点的姓名(name),然后因为收到上一个实现类的启发,于是直接在点中定义了两个Map,一个(targets)和一个(sources)分别存储以该点为起始点的键值对,和以该点为终点的键值对
- 设计点类checkRep:首先不能存在重复的点,且权值为正整数
- 设计vertice的toString()如图:
- 针对所有的rep写get方法
- 用编写好的vertice来实现ConcreteVerticesGraph
方法名称 | 实现 |
Add | 检查点集中是否已经存在,如果不存在则添加返回true,如果存在则返回false |
Set | 先检查set的边是否已经在点集里存在,如果不存在那么直接在函数开始就加上该点,然后在所有他指向的的返回0。如果不是,那么开始判断权值是否大于0, 大于0 的话则把权值改为现在的输入的权值,返回上一次权值;等于0则删除这条边,返回上一次权值。如果是第一次创建边那么返回0 |
Remove | 如果删除边在点集中那么首先删除该点,再次遍历所有的点如果点的target或者source中有这个名字的key则删除之,然后返回true,否则返回false |
Vertices | 返回vertices表中所有的名字即可 |
Sources | 直接调用getsources方法返回 |
Targets | 直接调用gettargets方法返回 |
ToString | 调用每个vertice列表里的vertice.toString()生成一个大字符串返回 |
我的编写的函数中并没有用到String特殊的方法,所以直接把所有String改为T泛型即可。
随意挑选实现类中的一个即可
任务要求利用之前实现的图,将语料库文件转化为一种图结构,并且根据输入的字符串在图中搜索可以插入的单词,完成诗句的扩展。
按照等价类划分测试:输入单行的诗文,多行的诗文,不输入诗文;没有最大的权值的边,有最大的权值的边;两者做笛卡尔积即可全覆盖
1.先构造这个语料库的图,每次从文件中读入一行,把文本按照“ ”划分,前一个是后一个单词的出发节点,如果不存在这个边,用set(source,target,1)方法来设置这条边,如果边集中已经存在,那么权值加1
2.根据这个图构造的你的诗文扩展,先把你输入的句子按照“ ”划分,以次判断前一个单词和后一个单词中间是否有边长为2的边,如果有,在这些边集中找到权值最大的边,然后将中间节点加入这两个单词中;如果权值都相等,那么随意挑选一个加入。如果没有边长为2的边则无需操作。
自带的main测试用例实现正确
使用本次实验实现的graph接口来替换掉第一次实验的friendshipgraph中的操作
addVertex()方法直接使用Graph中的add()方法实现:
addEdge()方法直接使用Graph中的set()方法实现,由于此题不带权,因此权值均设置为1
getDistance()没有太大变化,和之前一样利用广度优先搜索实现,只需要把存储邻接节点的表结构换为Map结构的方式即可。
只需要把不用的方法和变量删除即可
与实验一相同
与实验一相同,只需要把邻接表结构更换为Map
如何通过Git提交当前版本到GitHub上你的Lab3仓库:
git add .
git commit -m “xxx”
git push -u origin master
在这里给出你的项目的目录结构树状示意图: