JML(Java Modeling Language)是一种行为规范接口语言,经过使用不会被编译的注释形式,和固定关键字的语法,指定Java模块代码的行为。大致上包括如下三种要求:java
前置: @requires 子句定义了须要知足的条件。node
过程: @assignment 子句定义了能够改变的成员。算法
后置: @ensure 子句定义了方法要达到的效果。数组
此外,还有一些比较经常使用的的语法以下:数据结构
@pure 子句代表该方法无反作用,即仅具备查询功能架构
@constraint 子句定义了状态变化约束框架
@invariant 子句定义了全过程当中的不变式函数
\nothing 关键词代表该方法对类成员属性不进行修改工具
\result 关键词表明该方法的返回值学习
\forall表达式:全称量词修饰的表达式,表示对于给定范围内的元素,每一个元素都知足相应的约束。
\exists表达式: 存在量词修饰的表达式,表示对于给定范围内的元素,存在某个元素知足相应的约束。
\sum表达式:返回给定范围内的表达式的和。
\product表达式:返回给定范围内的表达式的连乘结果。
\max表达式:返回给定范围内的表达式的最大值。
\min表达式:返回给定范围内的表达式的最小值。
\num_of表达式:返回指定变量中知足相应条件的取值个数。
OpenJML:OpenJML能够对含有JML的代码进行编译 ,并提供不一样类型的选项进行检查。-esc能够静态检查可能出现的隐藏bug,-rac是运行时检查,-check则能够检查代码是否符合JML规格要求。
JMLUnitNG:能够根据代码中所写JML规范自动生成测试框架进行自动化测试。
测试结果以下:
本次做业彻底根据规格要求进行设计,为了减小查询的时间,采用了hashmap存放path与pathid。在distinctnode方面也采用了一个hashmap存储不一样的node,在方法getDistinctNodeCount()中,只需返回该hashmap的size便可,大大节省了查询的时间。两个map设计以下:
private HashMap<Integer, Path> map = new HashMap<>();
map的key为pathid,value为Path,这样能够节省查找时的时间。在removePath()方法中,须要对map进行遍历,根据重写的equals方法找到相应path便可。
private HashMap<Integer, Integer> dismap = new HashMap<>();
dismap的key为nodeid,value为该node出现的次数,这样在删除一条path时,能够将该path全部出现的点的次数减一,当次数为零时,从dismap中移除该点便可。
类图以下:
复杂度分析:
本次做业按照规格设计时遇到了许多困惑,在对最短路径求解时查询了许多算法,最后使用了florid算法。本次做业并未重构,在第一次做业进行简单修改就知足了题目要求。
设计以下:
private HashMap<Integer, Path> map = new HashMap<>(); private HashMap<Integer, Integer> dismap = new HashMap<>();
这两个map沿用第一次的设计,功能也相同。
private int[][] graph = new int[250][250]; private HashMap<Integer, Integer> castmap = new HashMap<>(); private int[] nodecount = new int[250]; private int flag = 0; private Floyd floyd;
类图设计:
复杂度分析:
本次做业有点相似曾经学过数据结构课程的最后一次地铁做业,在最短路径的求解上依旧采用floyd算法。在讨论区学习到了一种算法,根据这种算法结合floyd进行了计算。本次做业最终思路是将问题转化为图内边的权值问题,而后进行求解。本次做业并未重构,大部份内容沿用第二次做业的代码,部份内容从MyRailwaySystem类中移入了Floyd类。
算法内容以下:将每条path都变成彻底无向图,每条path内的每一个点都有直接到达该path内任意一点的距离,同时path内的每条边都要加上切换path时的额外权值。最终求出的值再减去一次换乘的额外权值,即为所求。
MyRailwaySystem设计以下:
private HashMap<Integer, Path> map = new HashMap<>(); private int flag = 0; private int blockNumber;
以上三个数据成员和前两次做业一直,blocknumber为连通块数量,根据并查集求解便可。
private Floyd leastOFtransfer = new Floyd(1); private Floyd leastOFfear = new Floyd(2); private Floyd leastOFunpleasant = new Floyd(3);
这三个数据成员即为本次做业的核心,构造函数传入构造模式(一个int型变量),以便区分额外权值。
Floyd设计以下:
private static int row = 120; private int[][] length = new int[row][row];// 任意两点之间路径长度 private int addweight;//额外权值 private static HashMap<Path, int[][]> pathHashMap = new HashMap<>();//存储每条path的彻底无向图 private static HashMap<Path, int[][]> unpleasantHashMap = new HashMap<>();//单独存储unpleasant的彻底无向图 private static HashMap<Integer, Integer> castmap = new HashMap<>();//映射map private static int[] nodecount = new int[row];//标记数组 private static HashMap<Integer, Integer> dismap = new HashMap<>();//计算distinctnode点的map private static int[][] graph = new int[row][row];//存入floyd计算结果 private static int[][] shortestLength = new int[row][row];//最短路径数组
类图设计:
复杂度分析:
第一次做业:本次做业强测只获得了80分,缘由是没考虑到课程组会利用时间卡数据,在不应进行计算的地方反复进行了计算,因此事件被拖慢了,可是综合设计是没有问题的。已经成功合并修复。
第二次做业:本次做业强测45分,由于没有吸收第一次的教训,致使本次做业依然犯了不应犯的错误,查询时反复计算,致使许多点都time_limited。已经成功合并修复。
第三次做业:本次做业强测95分,bug在于数据太大时,我所设定的无限大出如今了数据里,致使数据错误。已经成功合并修复。
规格撰写本质上体现了从上而下的设计思路,设计好大框架而后一点一点的去构建细节。在学习了JML以后,可以经过已给出的规格实现函数或者类所要求的功能,这是一种很棒的体验。可是规格自己的学习是较为困难的,有许多语法上的规定须要记忆,之后仍是要多多练习先写规格,再写代码,这样不会忘记本身设计的原始意图,别人读代码也会轻松不少。