OO第三单元总结

OO第三单元总结

梳理JML语言的理论基础、应用工具链状况

JML(Java Modeling Language)是一种行为规范接口语言,经过使用不会被编译的注释形式,和固定关键字的语法,指定Java模块代码的行为。大致上包括如下三种要求:java

前置: @requires 子句定义了须要知足的条件。node

过程: @assignment 子句定义了能够改变的成员。算法

后置: @ensure 子句定义了方法要达到的效果。数组

此外,还有一些比较经常使用的的语法以下:数据结构

@pure 子句代表该方法无反作用,即仅具备查询功能架构

@constraint 子句定义了状态变化约束框架

@invariant 子句定义了全过程当中的不变式函数

\nothing 关键词代表该方法对类成员属性不进行修改工具

\result 关键词表明该方法的返回值学习

\forall表达式:全称量词修饰的表达式,表示对于给定范围内的元素,每一个元素都知足相应的约束。

\exists表达式: 存在量词修饰的表达式,表示对于给定范围内的元素,存在某个元素知足相应的约束。

\sum表达式:返回给定范围内的表达式的和。

\product表达式:返回给定范围内的表达式的连乘结果。

\max表达式:返回给定范围内的表达式的最大值。

\min表达式:返回给定范围内的表达式的最小值。

\num_of表达式:返回指定变量中知足相应条件的取值个数。

JML的应用工具链:

OpenJML:OpenJML能够对含有JML的代码进行编译 ,并提供不一样类型的选项进行检查。-esc能够静态检查可能出现的隐藏bug,-rac是运行时检查,-check则能够检查代码是否符合JML规格要求。

JMLUnitNG:能够根据代码中所写JML规范自动生成测试框架进行自动化测试。

部署JMLUnitNG/JMLUnit,针对Graph接口的实现自动生成测试用例

测试结果以下:

三次做业架构设计

第一次做业架构设计

本次做业彻底根据规格要求进行设计,为了减小查询的时间,采用了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;
  • graph是一个二维数组,该数组是为了存储任意两点之间是否存在一条边,用于floyd算法。
  • castmap是考虑到nodeid的数量不会超过250,可是nodeid自己是一个int范围的数,因此采用了一个castmap,key为该点的nodeid,value为映射的值,value的范围为[0,250)
  • nodecount数组用来记录,在[0,250)之间的哪些值已经被映射,下标为映射的目标值,数组内存放标志位。在remove时要遍历dismap,若是该点出现的次数已经为0,就要删除这一映射,这样能够按照要求将nodeid个数严格控制在250之内。
  • flag为标志位,每次调用remove或是add方法都须要将flag置一,这样在每次计算新的floyd最短路径时,判断路径是否有添加或删除(即flag是否为1),若是flag为1则计算新最短路径,并将flag置0;若是flag为0,则不计算,采用上一次计算的最短路径。
  • floyd为存放Floyd算法的最终结果的一个对象。只有当flag置一时,才会调用他的构造方法,从新计算新的最短路径。

类图设计:

复杂度分析:

第三次做业架构设计

本次做业有点相似曾经学过数据结构课程的最后一次地铁做业,在最短路径的求解上依旧采用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];//最短路径数组

类图设计:

复杂度分析:

代码bug分析

第一次做业:本次做业强测只获得了80分,缘由是没考虑到课程组会利用时间卡数据,在不应进行计算的地方反复进行了计算,因此事件被拖慢了,可是综合设计是没有问题的。已经成功合并修复。

第二次做业:本次做业强测45分,由于没有吸收第一次的教训,致使本次做业依然犯了不应犯的错误,查询时反复计算,致使许多点都time_limited。已经成功合并修复。

第三次做业:本次做业强测95分,bug在于数据太大时,我所设定的无限大出如今了数据里,致使数据错误。已经成功合并修复。

规格撰写和理解的心得体会

规格撰写本质上体现了从上而下的设计思路,设计好大框架而后一点一点的去构建细节。在学习了JML以后,可以经过已给出的规格实现函数或者类所要求的功能,这是一种很棒的体验。可是规格自己的学习是较为困难的,有许多语法上的规定须要记忆,之后仍是要多多练习先写规格,再写代码,这样不会忘记本身设计的原始意图,别人读代码也会轻松不少。

相关文章
相关标签/搜索