我认为这一单元在难度上稍低于前两个单元,难度的降低主要体现在设计上,虽然本单元也需要考虑不少设计的问题,但设计难度要比前两单元低一点。不过这单元在算法方面难度有所提高,本人被tarjan算法弄晕了头,好不容易才搞明白,实现与debug又花了特别久,只能后悔数据结构学得不够好。在得分上三次作业分别是100,100,90,互测未出bug。这次的90给了我大大的教训:不要轻信别人提出的观点,要自己考察一番再做决定。
我得90的原因是qbs超时,当时在讨论群看到有同学说qbs直接并查集遍历查询不会超时,不需要在并查集中加入一个成员变量来记录Block数目,我没多想就相信了。结果强测最后两个点稍稍超时了一点,扣了10分非常心痛。我以后一定要仔细思考别人的观点,自己判断后再下决定,而不能盲从,负责任的终归只有自己一人。
下面进入正式分析环节。
一、JML理论基础及应用工具链
1.JML介绍
JML(Java Modeling Language)是一种用于规范Java程序行为的行为接口规范语言。JML为方法和类型的规格进行定义,为程序的形式化验证提供了基础,通过工具链可以实现静态检查和自动测试数据生成。
一般而言,JML有两种主要的用法:
- 开展规格化设计。这样交给代码实现人员的将不是可能带有内在模糊性的自然语言描述,而是逻辑严格的规格。
- 针对已有的代码实现,书写其对应的规格,从而提高代码的可维护性。这在遗留代码的维护方面具有特别重要的意义。
2. 理论基础
(1)注释结构
JML以javadoc注释的方式来表示规格,每行都以@起头。分为以下两种
1)行注释://@annotation
2)块注释:/*@ annotation @*/
(2)表达式
1)原子表达式
\result
表达式:方法执行的结果
\old( expr )
表达式:表达式 expr 方法执行前的值 \not_assigned(x,y,...)
表达式:用来表示括号中的变量是否在方法执行过程中被赋值
\type(type)
表达式:返回type
对应的类型
\typeof(expr)
表达式:返回expr
对应的类型
\not_modified(x,y,...)
表达式:括号中变量的取值在方法执行过程中未发生变化
\nonnullelements( container )
表达式: container
中存储的对象不会有 null
2)量化表达式
\forall
表达式:全称量词
\exists
表达式:存在量词
\sum
表达式:求和
\max
表达式:最大值
\min
表达式:最小值
(3)方法规格
1)前置条件(pre-condition):requires P
,要求调用者确保P为真
2)后置条件(post-condition):ensures P
,方法实现者确保方法执行的返回结果一定确保P为真
3)副作用范围限定(side-effects): assignable
或者modifiable
,方法在执行过程中会修改对象的属性数据或者类的静态成员数据
4)纯粹访问性的方法: pure
,不改变任何东西
5)抛出异常子句: signals
(4)操作符
1)子类型关系操作符:E1<:E2
,如果类型E1是类型E2的子类型(sub type),则该表达式的结果为真,否则为假。如果E1和E2是相同的类型,该表达式的结果也为真。
2)等价关系操作符:b_expr1<==>b_expr2
或者b_expr1<=!=>b_expr2
,其中b_expr1
和b_expr2
都是布尔表达式,这两个表达式的意思是b_expr1==b_expr2
或者b_expr1!=b_expr2
。可以看出,这两个操作符和Java中的==和!=具有相同的效果。
3)推理操作符:b_expr1== >b_expr2
或者b_expr2< ==b_expr1
,对于表达式b_expr1==>b_expr2
而言,当b_expr1==false
,或者b_expr1==true
且b_expr2==true
时,整个表达式的值为true 。
4)变量引用操作符
\nothing
指示一个空集
\everything
指示一个全集
2.应用工具链
- OpenJML:可以检查JML文档规格语法;
- SMT Solver:OpenJML的一种,用于验证代码和规格的等价性;
- JMLUnitNG:一款基于JML的单元测试工具,可以自动生成测试用例;
- Junit:用于进行单元测试,可编写和可重复运行的自动化测试。
二、SMT Slover验证
不得不吐槽SMT Slover的配置实在困难,网上教程太少,不用jdk8莫名报错(先头铁没换,后只能妥协)。各处查博客问同学后终于运行成功,结果如下两图所示。以下验证以MyPerson类的方法为例
容易发现报出来的Warning主要有以下三类:
1. The prover cannot establish an assertion
2. Precondition conjunct is false
3. Associated declaration
除此之外也在MyGroup类和MyNetWork类进行了验证,Warning都为以上三种。
参考他人博客中指出的SMT无法对Array与ArrayList之间进行转换,很不智能。我便试着通过把需要转换的结构修改成不需要转换的结构后再次运行,然而Warning仍没有变少,询问大佬也是无果,只能归结为SMT长久不维护的谜之原因。
三、JMLUnitNG自动测试
使用JMLUnitNG体验不错,在按照教程配置后成功运行,对MyGroup中的各个方法进行自动测试,没有出现Bug。
发现其非常喜欢测试边界情况,不过课程组限定了数据的范围,所以这些测试对于本次作业没有太大的用处,不过对于实际工程中应该还是有帮助的,起码花出去的时间成本比较低。
不过我们当然不能依赖它,肯定还是要自己写测试样例,它提供的测试样例局限性还是比较大的。
四、构架设计分析
1. 第一次作业
注:从左至右分别为ev(G), iv(G), v(G),下同
com.oocourse.spec1.exceptions.EqualPersonIdException.EqualPersonIdException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec1.exceptions.EqualPersonIdException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec1.exceptions.EqualRelationException.EqualRelationException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec1.exceptions.EqualRelationException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec1.exceptions.PersonIdNotFoundException.PersonIdNotFoundException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec1.exceptions.PersonIdNotFoundException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec1.exceptions.RelationNotFoundException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec1.exceptions.RelationNotFoundException.RelationNotFoundException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec1.main.Runner.addPerson() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec1.main.Runner.addRelation() | 1.0 | 3.0 | 3.0 |
com.oocourse.spec1.main.Runner.compareAge() | 1.0 | 2.0 | 4.0 |
com.oocourse.spec1.main.Runner.compareName() | 1.0 | 2.0 | 4.0 |
com.oocourse.spec1.main.Runner.queryAcquaintanceSum() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec1.main.Runner.queryCircle() | 1.0 | 3.0 | 3.0 |
com.oocourse.spec1.main.Runner.queryConflict() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec1.main.Runner.queryNameRank() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec1.main.Runner.queryPeopleSum() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec1.main.Runner.queryValue() | 1.0 | 3.0 | 3.0 |
com.oocourse.spec1.main.Runner.run() | 1.0 | 12.0 | 12.0 |
com.oocourse.spec1.main.Runner.Runner(Class,Class) | 1.0 | 1.0 | 1.0 |
MainClass.main(String[]) | 1.0 | 1.0 | 1.0 |
MyNetwork.addPerson(Person) | 3.0 | 2.0 | 3.0 |
MyNetwork.addRelation(int,int,int) | 6.0 | 15.0 | 18.0 |
MyNetwork.compareAge(int,int) | 2.0 | 3.0 | 3.0 |
MyNetwork.compareName(int,int) | 2.0 | 3.0 | 3.0 |
MyNetwork.contains(int) | 3.0 | 2.0 | 3.0 |
MyNetwork.getPerson(int) | 4.0 | 4.0 | 4.0 |
MyNetwork.isCircle(int,int) | 6.0 | 6.0 | 8.0 |
MyNetwork.MyNetwork() | 1.0 | 1.0 | 1.0 |
MyNetwork.queryAcquaintanceSum(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryConflict(int,int) | 2.0 | 3.0 | 3.0 |
MyNetwork.queryNameRank(int) | 2.0 | 3.0 | 4.0 |
MyNetwork.queryPeopleSum() | 1.0 | 1.0 | 1.0 |
MyNetwork.queryValue(int,int) | 4.0 | 7.0 | 9.0 |
MyPerson.compareTo(Person) | 1.0 | 1.0 | 1.0 |
MyPerson.equals(Object) | 2.0 | 2.0 | 3.0 |
MyPerson.getAcquaintance() | 1.0 | 1.0 | 1.0 |
MyPerson.getAcquaintanceSum() | 1.0 | 1.0 | 1.0 |
MyPerson.getAge() | 1.0 | 1.0 | 1.0 |
MyPerson.getCharacter() | 1.0 | 1.0 | 1.0 |
MyPerson.getId() | 1.0 | 1.0 | 1.0 |
MyPerson.getName() | 1.0 | 1.0 | 1.0 |
MyPerson.getValue() | 1.0 | 1.0 | 1.0 |
MyPerson.isLinked(Person) | 4.0 | 2.0 | 4.0 |
MyPerson.MyPerson(int,String,BigInteger,int) | 1.0 | 1.0 | 1.0 |
MyPerson.queryValue(Person) | 3.0 | 3.0 | 3.0 |
Total | 77.0 | 112.0 | 129.0 |
Average | 1.673913043478261 | 2.4347826086956523 | 2.8043478260869565 |
分析:
第一次作业非常简单,主要目的应该是让同学们熟悉JML,在读懂JML后的实现非常轻松。MyNetWork中我使用的是ArrayList来存储Person(之后的作业为了提高效率弃用),由于这次作业非常简单,数据结构上的要求比较宽松,MyPerson中的value与acquaintance都使用的ArrayList,之后也都弃置了。现在看来当时就应该考虑到性能问题,也不用在之后的两次作业中重构了。
唯一需要考虑的地方在于isCircle,这一次我使用的是bfs算法,bfs算法已经足够满足这次的效率要求,不过之后却不行了,这也导致了我之后的重构。下次做第一次作业理应好好思考后路减少重构了。
复杂度分析上大部分的结果都不错,只有addRelation复杂度较高。
2. 第二次作业
com.oocourse.spec2.exceptions.EqualGroupIdException.EqualGroupIdException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.exceptions.EqualGroupIdException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.exceptions.EqualPersonIdException.EqualPersonIdException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.exceptions.EqualPersonIdException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.exceptions.EqualRelationException.EqualRelationException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.exceptions.EqualRelationException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.exceptions.GroupIdNotFoundException.GroupIdNotFoundException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.exceptions.GroupIdNotFoundException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.exceptions.PersonIdNotFoundException.PersonIdNotFoundException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.exceptions.PersonIdNotFoundException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.exceptions.RelationNotFoundException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.exceptions.RelationNotFoundException.RelationNotFoundException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.main.Runner.addGroup() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec2.main.Runner.addPerson() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec2.main.Runner.addRelation() | 1.0 | 3.0 | 3.0 |
com.oocourse.spec2.main.Runner.addtoGroup() | 1.0 | 4.0 | 4.0 |
com.oocourse.spec2.main.Runner.compareAge() | 1.0 | 2.0 | 4.0 |
com.oocourse.spec2.main.Runner.compareName() | 1.0 | 2.0 | 4.0 |
com.oocourse.spec2.main.Runner.queryAcquaintanceSum() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec2.main.Runner.queryCircle() | 1.0 | 3.0 | 3.0 |
com.oocourse.spec2.main.Runner.queryConflict() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec2.main.Runner.queryGroupAgeMean() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec2.main.Runner.queryGroupAgeVar() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec2.main.Runner.queryGroupConflictSum() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec2.main.Runner.queryGroupPeopleSum() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec2.main.Runner.queryGroupRelationSum() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec2.main.Runner.queryGroupSum() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.main.Runner.queryGroupValueSum() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec2.main.Runner.queryNameRank() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec2.main.Runner.queryPeopleSum() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec2.main.Runner.queryValue() | 1.0 | 3.0 | 3.0 |
com.oocourse.spec2.main.Runner.run() | 1.0 | 21.0 | 21.0 |
com.oocourse.spec2.main.Runner.Runner(Class,Class,Class) | 1.0 | 1.0 | 1.0 |
MyGroup.addPerson(Person) | 1.0 | 2.0 | 3.0 |
MyGroup.equals(Object) | 2.0 | 2.0 | 3.0 |
MyGroup.getAgeMean() | 2.0 | 2.0 | 2.0 |
MyGroup.getAgeVar() | 2.0 | 2.0 | 2.0 |
MyGroup.getConflictSum() | 1.0 | 1.0 | 1.0 |
MyGroup.getId() | 1.0 | 1.0 | 1.0 |
MyGroup.getIndex() | 1.0 | 1.0 | 1.0 |
MyGroup.getRelationSum() | 1.0 | 1.0 | 1.0 |
MyGroup.getSize() | 1.0 | 1.0 | 1.0 |
MyGroup.getValueSum() | 1.0 | 1.0 | 1.0 |
MyGroup.hasPerson(Person) | 1.0 | 1.0 | 1.0 |
MyGroup.MyGroup(int) | 1.0 | 1.0 | 1.0 |
MyGroup.setIndex(int) | 1.0 | 1.0 | 1.0 |
MyGroup.setRelationSum(int) | 1.0 | 1.0 | 1.0 |
MyGroup.setValueSum(int) | 1.0 | 1.0 | 1.0 |
MyNetwork.addGroup(Group) | 2.0 | 3.0 | 3.0 |
MyNetwork.addPerson(Person) | 2.0 | 2.0 | 2.0 |
MyNetwork.addRelation(int,int,int) | 6.0 | 17.0 | 20.0 |
MyNetwork.addtoGroup(int,int) | 5.0 | 8.0 | 9.0 |
MyNetwork.compareAge(int,int) | 2.0 | 3.0 | 3.0 |
MyNetwork.compareName(int,int) | 2.0 | 3.0 | 3.0 |
MyNetwork.contains(int) | 1.0 | 1.0 | 1.0 |
MyNetwork.getGroup(int) | 1.0 | 1.0 | 1.0 |
MyNetwork.getPerson(int) | 1.0 | 1.0 | 1.0 |
MyNetwork.isCircle(int,int) | 3.0 | 3.0 | 4.0 |
MyNetwork.MyNetwork() | 1.0 | 1.0 | 1.0 |
MyNetwork.queryAcquaintanceSum(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryConflict(int,int) | 2.0 | 3.0 | 3.0 |
MyNetwork.queryGroupAgeMean(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryGroupAgeVar(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryGroupConflictSum(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryGroupPeopleSum(int) | 3.0 | 3.0 | 3.0 |
MyNetwork.queryGroupRelationSum(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryGroupSum() | 1.0 | 1.0 | 1.0 |
MyNetwork.queryGroupValueSum(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryNameRank(int) | 2.0 | 3.0 | 4.0 |
MyNetwork.queryPeopleSum() | 1.0 | 1.0 | 1.0 |
MyNetwork.queryValue(int,int) | 4.0 | 7.0 | 9.0 |
MyPerson.compareTo(Person) | 1.0 | 1.0 | 1.0 |
MyPerson.equals(Object) | 2.0 | 2.0 | 3.0 |
MyPerson.getAcquaintance() | 1.0 | 1.0 | 1.0 |
MyPerson.getAcquaintanceSum() | 1.0 | 1.0 | 1.0 |
MyPerson.getAge() | 1.0 | 1.0 | 1.0 |
MyPerson.getCharacter() | 1.0 | 1.0 | 1.0 |
MyPerson.getId() | 1.0 | 1.0 | 1.0 |
MyPerson.getName() | 1.0 | 1.0 | 1.0 |
MyPerson.isLinked(Person) | 3.0 | 1.0 | 3.0 |
MyPerson.MyPerson(int,String,BigInteger,int) | 1.0 | 1.0 | 1.0 |
MyPerson.queryValue(Person) | 2.0 | 2.0 | 2.0 |
UnionFind.addRelation(int,int) | 5.0 | 5.0 | 9.0 |
UnionFind.getRoot(Integer) | 1.0 | 2.0 | 2.0 |
UnionFind.isRelated(int,int) | 3.0 | 3.0 | 4.0 |
UnionFind.UnionFind() | 1.0 | 1.0 | 1.0 |
Total | 127.0 | 191.0 | 213.0 |
Average | 1.4767441860465116 | 2.2209302325581395 | 2.4767441860465116 |
分析:
第二次作业也比较容易,不过已经比第一次作业加了不少难度了,在读懂JML后还需要仔细地考虑算法能否满足要求。MyNetWork中我改用了HashMap来存储Person(为了提高查找的效率),由于这次作业对性能的要求,数据结构上的要求比较紧张,MyPerson中的acquaintance也改用了HashMap。
由于性能的需求,为了实现isCircle而使用了并查集,这也是我第一次接触并查集,学习了一番后还是比较顺利地实现出来了。另外在MyGroup类有众多查询平均值,总和之类的实现需求,直接每次遍历肯定是不行的,因此添加了成员变量来进行存储。
复杂度分析上大部分的结果都不错,同样只有addRelation复杂度较高。
3. 第三次作业
com.oocourse.spec3.exceptions.EqualGroupIdException.EqualGroupIdException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.exceptions.EqualGroupIdException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.exceptions.EqualPersonIdException.EqualPersonIdException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.exceptions.EqualPersonIdException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.exceptions.EqualRelationException.EqualRelationException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.exceptions.EqualRelationException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.exceptions.GroupIdNotFoundException.GroupIdNotFoundException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.exceptions.GroupIdNotFoundException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.exceptions.PersonIdNotFoundException.PersonIdNotFoundException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.exceptions.PersonIdNotFoundException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.exceptions.RelationNotFoundException.print() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.exceptions.RelationNotFoundException.RelationNotFoundException() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.main.Runner.addGroup() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.addPerson() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.addRelation() | 1.0 | 3.0 | 3.0 |
com.oocourse.spec3.main.Runner.addtoGroup() | 1.0 | 4.0 | 4.0 |
com.oocourse.spec3.main.Runner.borrowFrom() | 1.0 | 3.0 | 3.0 |
com.oocourse.spec3.main.Runner.compareAge() | 1.0 | 2.0 | 4.0 |
com.oocourse.spec3.main.Runner.compareName() | 1.0 | 2.0 | 4.0 |
com.oocourse.spec3.main.Runner.delFromGroup() | 1.0 | 4.0 | 4.0 |
com.oocourse.spec3.main.Runner.query_money() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryAcquaintanceSum() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryAgeSum() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.main.Runner.queryBlockSum() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.main.Runner.queryCircle() | 1.0 | 3.0 | 3.0 |
com.oocourse.spec3.main.Runner.queryConflict() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryGroupAgeMean() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryGroupAgeVar() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryGroupConflictSum() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryGroupPeopleSum() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryGroupRelationSum() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryGroupSum() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.main.Runner.queryGroupValueSum() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryMinPath() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryNameRank() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryPeopleSum() | 1.0 | 1.0 | 1.0 |
com.oocourse.spec3.main.Runner.queryStrongLinked() | 1.0 | 2.0 | 2.0 |
com.oocourse.spec3.main.Runner.queryValue() | 1.0 | 3.0 | 3.0 |
com.oocourse.spec3.main.Runner.run() | 1.0 | 28.0 | 28.0 |
com.oocourse.spec3.main.Runner.Runner(Class,Class,Class) | 1.0 | 1.0 | 1.0 |
Edge.Edge(int,int) | 1.0 | 1.0 | 1.0 |
Edge.getId1() | 1.0 | 1.0 | 1.0 |
Edge.getId2() | 1.0 | 1.0 | 1.0 |
Edge.hashCode() | 1.0 | 1.0 | 1.0 |
MainClass.main(String[]) | 1.0 | 1.0 | 1.0 |
MyGroup.addPerson(Person) | 1.0 | 2.0 | 3.0 |
MyGroup.delPerson(Person) | 1.0 | 2.0 | 3.0 |
MyGroup.equals(Object) | 2.0 | 2.0 | 3.0 |
MyGroup.getAgeMean() | 2.0 | 2.0 | 2.0 |
MyGroup.getAgeVar() | 2.0 | 2.0 | 2.0 |
MyGroup.getConflictSum() | 1.0 | 1.0 | 1.0 |
MyGroup.getId() | 1.0 | 1.0 | 1.0 |
MyGroup.getIndex() | 1.0 | 1.0 | 1.0 |
MyGroup.getRelationSum() | 1.0 | 1.0 | 1.0 |
MyGroup.getSize() | 1.0 | 1.0 | 1.0 |
MyGroup.getValueSum() | 1.0 | 1.0 | 1.0 |
MyGroup.hasPerson(Person) | 1.0 | 1.0 | 1.0 |
MyGroup.MyGroup(int) | 1.0 | 1.0 | 1.0 |
MyGroup.setIndex(int) | 1.0 | 1.0 | 1.0 |
MyGroup.setRelationSum(int) | 1.0 | 1.0 | 1.0 |
MyGroup.setValueSum(int) | 1.0 | 1.0 | 1.0 |
MyNetwork.addGroup(Group) | 2.0 | 3.0 | 3.0 |
MyNetwork.addPerson(Person) | 2.0 | 2.0 | 2.0 |
MyNetwork.addRelation(int,int,int) | 6.0 | 17.0 | 20.0 |
MyNetwork.addtoGroup(int,int) | 5.0 | 8.0 | 9.0 |
MyNetwork.borrowFrom(int,int,int) | 4.0 | 5.0 | 7.0 |
MyNetwork.compareAge(int,int) | 2.0 | 3.0 | 3.0 |
MyNetwork.compareName(int,int) | 2.0 | 3.0 | 3.0 |
MyNetwork.contains(int) | 1.0 | 1.0 | 1.0 |
MyNetwork.delFromGroup(int,int) | 5.0 | 6.0 | 7.0 |
MyNetwork.getGroup(int) | 1.0 | 1.0 | 1.0 |
MyNetwork.getPerson(int) | 1.0 | 1.0 | 1.0 |
MyNetwork.isCircle(int,int) | 3.0 | 3.0 | 4.0 |
MyNetwork.MyNetwork() | 1.0 | 1.0 | 1.0 |
MyNetwork.qaueryBlockSum() | 5.0 | 4.0 | 7.0 |
MyNetwork.queryAcquaintanceSum(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryAgeSum(int,int) | 1.0 | 2.0 | 4.0 |
MyNetwork.queryBlockSum() | 1.0 | 1.0 | 1.0 |
MyNetwork.queryConflict(int,int) | 2.0 | 3.0 | 3.0 |
MyNetwork.queryGroupAgeMean(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryGroupAgeVar(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryGroupConflictSum(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryGroupPeopleSum(int) | 3.0 | 3.0 | 3.0 |
MyNetwork.queryGroupRelationSum(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryGroupSum() | 1.0 | 1.0 | 1.0 |
MyNetwork.queryGroupValueSum(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryMinPath(int,int) | 9.0 | 7.0 | 10.0 |
MyNetwork.queryMoney(int) | 2.0 | 2.0 | 2.0 |
MyNetwork.queryNameRank(int) | 2.0 | 3.0 | 4.0 |
MyNetwork.queryPeopleSum() | 1.0 | 1.0 | 1.0 |
MyNetwork.queryStrongLinked(int,int) | 3.0 | 4.0 | 4.0 |
MyNetwork.queryValue(int,int) | 4.0 | 7.0 | 9.0 |
MyNetwork.Tarjan(int,int,boolean) | 8.0 | 14.0 | 17.0 |
MyPerson.compareTo(Person) | 1.0 | 1.0 | 1.0 |
MyPerson.equals(Object) | 2.0 | 2.0 | 3.0 |
MyPerson.getAcquaintance() | 1.0 | 1.0 | 1.0 |
MyPerson.getAcquaintanceSum() | 1.0 | 1.0 | 1.0 |
MyPerson.getAge() | 1.0 | 1.0 | 1.0 |
MyPerson.getCharacter() | 1.0 | 1.0 | 1.0 |
MyPerson.getId() | 1.0 | 1.0 | 1.0 |
MyPerson.getName() | 1.0 | 1.0 | 1.0 |
MyPerson.isLinked(Person) | 3.0 | 1.0 | 3.0 |
MyPerson.MyPerson(int,String,BigInteger,int) | 1.0 | 1.0 | 1.0 |
MyPerson.queryValue(Person) | 2.0 | 2.0 | 2.0 |
Relationship.getId() | 1.0 | 1.0 | 1.0 |
Relationship.getValue() | 1.0 | 1.0 | 1.0 |
Relationship.Relationship(int,int) | 1.0 | 1.0 | 1.0 |
UnionFind.addBlockSum() | 1.0 | 1.0 | 1.0 |
UnionFind.addRelation(int,int) | 5.0 | 5.0 | 9.0 |
UnionFind.getBlockSum() | 1.0 | 1.0 | 1.0 |
UnionFind.getRoot(Integer) | 1.0 | 2.0 | 2.0 |
UnionFind.isRelated(int,int) | 3.0 | 3.0 | 4.0 |
UnionFind.UnionFind() | 1.0 | 1.0 | 1.0 |
Total | 183.0 | 270.0 | 307.0 |
Average | 1.6194690265486726 | 2.3893805309734515 | 2.7168141592920354 |
分析:
第三次作业比较困难了,相比前两次作业加了不少难度,需要仔细地考虑算法能否满足要求,还要学习不少新的算法。这一次作业用延续了并查集的使用,并且实现了tarjan算法,这一算法实在是很难实现,进行了多次测试和调试才成功。
这一次作业中我由于qbs而强测超时了两个点,实在是不应该。我过于疏忽了,对于这类查询总和的方法应该立马想到通过添加成员变量来实现。设计需谨慎,下次一定要避免这样的惨剧发生。
复杂度分析上大部分的结果都不错,同样只有addRelation复杂度较高。
五、Bug与修复
三次作业中只在第三次强测时由于qbs设计不当而超时,互测中未被发现错误。
在hack他人方面,很遗憾,我没有成功。虽然我实现了对另外7人的自动化测试,不过都没有跑出bug,使用边界数据也没有hack成功。
六、心得体会
1. 要学好JML一定要理清楚所有的基本概念,一开始我由于对基本概念不熟悉而效率低下,希望后人引以为戒。
2. 实现时一定要仔细仔细阅读JML,确认所有细节后再下手,否则很容易南辕北辙。
3. 一定要在第一次作业就考虑到性能问题,否则之后等待你的只有重构!
4. 自主思考问题,对于他人的观点一定仔细斟酌再采纳!