标签:details 结果 检测 构造 因此 rri pre 方法 最小生成树
---恢复内容开始---
CSDN博客链接
@
JML(Java Modeling Language):对Java程序进行规格化设计的一种表示语言。JML是一种行为接口规格语言 (Behavior Interface Speci?cation Language,BISL),基于Larch方法构建。BISL提供了对方法和类型的规格定义
手段。所谓接口即一个方法或类型外部可见的内容。
软件系统中的元素之间相互合作以及“责任”与“义务”
method A(){
assert(前置条件)
do something
assert(后置条件)
return
}
具体使用详见《JML Level 0手册》
很遗憾,电脑不兼容openJML,按照教程严格执行,却一直失败:
public int hashCode() {
int[] array = new int[3];
array[0] = min;
array[1] = max;
array[2] = pathId;
return Arrays.hashCode(array);
}
@Test
public void hashCodeTest() {
assertNotEquals(new Edge(-69,54,1).hashCode(),
new Edge(-68,23,1).hashCode());
//Values should be different. Actual: -34843
HashSet<Integer> set = new HashSet<>();
for (int i = -50; i < 50; i++)
for (int j = -50; j < 50; j++) {
Edge edge = new Edge(i, j, 1);
set.add(edge.hashCode());
}
assertEquals(set.size(), 5050);
//java.lang.AssertionError:
// Expected :2704
// Actual :5050 i!=j: (100+1)*100/2
}
public int hashCode() {
return (min + "," + max + "," + pathId).hashCode();
}
@Test
public void getLeastTransferCountTest() {
Path path = new MyPath(1,2,3);
MyRailwaySystem system = new MyRailwaySystem();
system.addPath(path);
path = new MyPath(2,4,5,6);
system.addPath(path);
path = new MyPath(3,5);
system.addPath(path);
try {
assertEquals(system.getLeastTransferCount(1,6),1);
//java.lang.AssertionError:
//Expected :2
//Actual :1
} catch (Exception e) {
e.printStackTrace();
}
}
根据说明信息,发现在dijstra更新过程中出现错误,在bug修复处分析了具体原因及解决方式。
本单元作业要求依次实现四个类:
其中,MyPathContainer是MyPath的容器,并且实现了MyGraph的部分功能。因此,MyGraph中以MyPathContainer作为组成元素之一。同理,MyRailwayStation将MyGraph作为组成元素之一。各类包含关系如下:
在后续迭代过程中,不对前面实现过的类进行修改,仅是扩展添加新的属性及方法(遵循OCP原则:面对需求,对程序的改动是通过增加新代码进行的,而不是改变原来的代码。)
本次作业比较关键的几个方法为:
DISTINCT_NODE_COUNT
时都重新计算一遍,所花的时间复杂度是不能承受的。最开始我就是直接遍历,导致第一次强测爆40private HashMap<Integer, Integer> nmap = new HashMap<>();
//node的容器<node,number(node出现在各个路径中的次数)>
DISTINCT_NODE_COUNT
时直接返回nmap.size();
o(v+e)
,对全图搜索复杂度为o(v(v+e))
private HashMap<Integer, HashSet<Integer>> linkMap;
private HashMap<Integer, HashMap<Integer, Integer>> disMap;
private HashMap<Integer, Edge> edgeMap;//hashCode(edge)-->edge(a,b)
o(v+e)
Node
,组成链表结构:是四元组<node(Integer),value(Integer),edge(Edge),next(Node)>for(Integer edgeHashCode: linkMap.get(arrive.getNode()))
Class | Cyclic | Dcy | Dcy* |
Dpt | Dpt* |
---|---|---|---|---|---|
Edge | 0 | 0 | 0 | 3 | 5 |
Main | 2 | 2 | 6 | 2 | 3 |
MyGraph | 2 | 3 | 6 | 1 | 3 |
MyGraphTest | 0 | 0 | 0 | 0 | 0 |
MyPath | 0 | 0 | 0 | 2 | 4 |
MyPathContainer | 0 | 0 | 0 | 1 | 4 |
MyRailwaySystem | 2 | 4 | 6 | 2 | 3 |
MyRailwaySystemTest | 0 | 2 | 7 | 0 | 0 |
Node | 0 | 1 | 1 | 1 | 4 |
均在正常范围内
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
MyGraph.isConnected(int,int) | 4 | 2 | 5 |
MyGraph.nodeEdgeOk(int) | 4 | 3 | 4 |
MyRailwaySystem.getLeast(int,int,int) | 5 | 3 | 5 |
MyRailwaySystem.renewNodeMap(int,int) | 3 | 13 | 14 |
Node.add(Node) | 5 | 6 | 6 |
其中MyRailwaySystem.renewNodeMap
方法,即对于单源的dijstra方法长50行,为了兼容3个搜索,分支很多,而错误也正是出现在这里。
以后任意一个方法,行数最好不要超过30行,秉承SRP(单一职责原则),只做出一个行为,然后通过封装和组合达到最终实现行为的目的。
(前面已经测试过)
最后发现node=6处value为2,实际上value应该为1
在HashMap数据结构中,如果访问的key值不在其中,函数会返回null,而不是抛出异常,而后对null调用函数会报错NullPointerException
。因此在这里常常出现诡异的bug,以后使用get时要小心,更好的方式是使用getOrDefault
,没有key值就给出默认的数据。
此外,对于HashMap套HashMap现象,连续使用两次get(),会造成意想不到的错误,不如先将乱序节点通过一个HashMap映射到从1开始的正整数上,然后直接使用二维静态数组。
JML是一种先进的契约式设计模式,将设计和实现不可跨越的鸿沟大幅减小。大体上解决问题分为从需求到设计,从设计到实现两个过程。而JML规范地描述了代码需要执行的约束条件,可以说是一种LLR(Low-Level Request)。
实际上,个人感觉JML更偏向于需求,而非设计。因为不管是你需要具体的数据结构,还是算法,都需要个人亲自去定义。并且为了描述一个需求,用大段大段的代码去规范和描述也不是一个简单的任务。很可能需要多层抽象,甚至有时根本找不出一个描述需求的严格的表达方式。写规格本身都要比实现一个需求难上许多。
但是比较受用的是自动测试生成JUnit,对类中的某一个具体的函数进行测试。虽然直接在控制台输入输出也很有效,但那样测完一次就结束了,没有办法对测试集进行管理。也没有办法在扩展修改了类以后保证类的兼容性。
总之,这一个单元是相当革新的,业界缺乏成熟的代码规格化设计方式,网络上对契约式设计也鲜有听闻,但是以后可能会日渐成熟。
---恢复内容结束---
标签:details 结果 检测 构造 因此 rri pre 方法 最小生成树
原文地址:https://www.cnblogs.com/RyanSun17373259/p/10908267.html