zoukankan      html  css  js  c++  java
  • OO第三单元总结:JML

    第三单元——jmljunit与图



    〇、问题描述

    ​ 本单元主题为JML的学习,问题载体为一个无向图路径管理系统。在三次作业种,情景不变,需求递增。因此需要在层次上做好安排。


    一、JML语言

    理论基础(Level 0)
    • 注释结构

      // @annotation 行注释

      /* @annotation*/ 块注释

    • JML表达式

      • 原子表达式

        esult 方法执行后的返回值

        old(expr) 表达式expr在方法执行前的值

        ot_assigned(expr) 表达式expr是否被赋值

        ot_modified(x,y,...) 表达式expr是否变化

        onnullelements( container ) 表达式:表示 container 对象中存储的对象不会有 null

        ype(type) 表达式:返回类型type对应的类型(Class)

      • 量化表达式

        forall 全称修饰

         (forall int i,j; 0 <= i && i < j && j < 10; a[i] < a[j])
        

        exists 存在修饰

         (exists int i; 0 <= i && i < 10; a[i] < 0)
        

        sum 给定范围内的表达式的和

         (sum int i; 0 <= i && i < 5; i)
        

        product 给定范围内的表达式的连乘结果

        max min 给定范围内的表达式的最大/小值

        um_of 指定变量中满足相应条件的取值个数

      • 集合表达式

      • 操作符

        <: 子类型关系操作符

        <==> <=!=>等价关系操作符

        ==> <== 推理操作符

        othing everything 变量引用操作符

    • 方法规格

      requires 前置条件

      ensures 后置条件

      assignable 可赋值

      modifiable 可修改

      public normal_behavior 正常功能

      signals 抛出异常

    • 类型规格

      invariant 不变式

      constraint 状态变化约束

    应用工具链

    lowa State JML : 提供了一个断言检查编译器jmlc,将JML注释转换为运行时的断言;

    jmldoc: 文档生成器,用于生成Javadoc文档,增加了来自JML注释的额外信息。

    jmlunit: 单元测试生成器可以从JML注释中生成JUnit测试代码。


    二、JMLUnitNG/JMLUnit

    public class Demo {
            /*@ public normal_behaviour
              @ ensures 
    esult == a + b;
              @*/
            public static int add(int a, int b) {
                return a + b;
            }
    
            public static void main(String[] args) {
                add(12,3);
            }           
    }
    

    [TestNG] Running:
    Command line suite

    Passed: racEnabled()
    Passed: constructor Demo()
    Passed: static add(-2147483648, -2147483648)
    Passed: static add(0, -2147483648)
    Passed: static add(2147483647, -2147483648)
    Passed: static add(-2147483648, 0)
    Passed: static add(0, 0)
    Passed: static add(2147483647, 0)
    Passed: static add(-2147483648, 2147483647)
    Passed: static add(0, 2147483647)
    Passed: static add(2147483647, 2147483647)
    Passed: static main(null)
    Passed: static main({})

    ===============================================
    Command line suite
    Total tests run: 13, Failures: 0, Skips: 0


    三、程序设计

    类的设计——继承与递进
    • 简析三次作业涉及到的指令及实现方式:

      • 第一次:HashMap管理路径

        // 两个对应的 HashMap 存储,加快查找
        private HashMap<Integer/*id*/,MyPath/*path*/> pathList;
        private HashMap<MyPath/*path*/,Integer/*id*/> pidList;
        // 在添加和删除时管理总点数,分摊复杂度
        private HashMap<Integer/*node*/,NumberOfNode/*number of node*/> distinct;
        
        // hashcode的设定
        /*path*/
        @Override
            public int hashCode() {
                return nodes.hashCode();
            }
        /*integer*/
        	Integer.hashCode();
        
        • 添加删除类 O(n)

          在两个表中添加/删除路径;管理节点数目。包括:

          • 添加路径
          • 删除路径
          • 根据id删除
        • 查询类 O(1)

          包括:

          • 查询id
          • 查询路径
          • 获取总路径数
          • 根据id获取路径大小
          • 根据结点序列判断容器是否包含路径
          • 根据路径id判断容器是否包含路径
          • 容器内不同结点个数
          • 路径中是否包含某个结点
        • 根据id获取不同节点个数 O(n)

          path内排序+遍历第一次为O(n),其后为O(1)

        • 根据字典序比较两个路径的大小关系 O(n)

      • 第二次:HashMap存储邻接表管理无向图

        // 邻接表:边权均为1的无向图
        private 
            HashMap<Integer/*起点*/,HashMap<Integer/*终点*/,Integer/*边数*/>> 
            reachable= new HashMap<>();
        
        • 边的存在性 O(1)

        • bfs 搜索 O(v+e)

          包括:

          • 两个结点是否连通

            最短路径存在

          • 两个结点之间的最短路径

      • 第三次:UndirectedGraph

        含有图的嵌套关系;图的连接状态相同但边权不同。新增一类专门管理。

        abstract class UndirectedGraph {
            // 无向图
            private HashMap<Integer/*point*/,HashMap<Integer/*point*/,Integer/*weight*/>> undirectedGraph;
            // 缓存区
            private HashMap<Integer/*point*/,HashMap<Integer/*point*/,Integer/*weight*/>> cache;
            private bfs(){}
            private spfa(){}
            ...
        }
        

        以下复杂度讨论均不考虑缓存查找。(重复查询时O(1)

        • 连通块数量

          涂色

        • spfa

          本质上都是带最短路径的问题。。。以前的沙雕方法都重写了。

          • 最低票价
          • 最少换乘次数
          • 最少不满意度
          • 最短路径
          • 两点连通性
    • 三次架构

      • 第一次:哈希表+规格方法
      • 第二次:添加可达表,原有方法不变
      • 第三次:添加图,重写查找算法相关方法
    算法
    • 第二次:bfs

    • 第三次:每条path内部先构建好小图,即建立好所有的边,这样在每一条边上加上换乘权值,搜最短路 ( spfa ) 就行。共需三个权值不同的图。

      因为查询指令较多,应每次搜索都将当前起点的所有终点最短路都放入缓存。每当图结构更改应该清空缓存。


    四、BUG分析

    ​ (本地bug)写第三次作业时,bfs写成找到目标终点即停止:

    while (size != 0) {
        if(fr==to) return;
        //...
        for (Integer x : keySet()) {
            //...
        }
    }
    

    ​ 导致第二次搜索时进行不下去。应改成一次性搜索完所有终点。


    五、心得体会

    ​ 对于jml,语法是相对简单,理解也相对容易。难点在于自己写出一份规范的规格。因为写规格的成本比写代码高出太多,我对jml仍仅仅停留在了解阶段,还需要更多的学习。毕竟,第三单元的作业架构严格来说几乎没有自己参与……由此也可见得架构对于程序正确性、效率和可扩展性的重要性。

  • 相关阅读:
    如何描述一个前端开发程序员
    解决电脑性能一般,打开webstorm后,电脑比较卡的问题
    HTML5的5个的新特性
    js 数组的拼接
    移动端性能
    如何学习前端
    实战:上亿数据如何秒查
    读懂Java中的Socket编程
    远程管理软件
    dedecms 安装后 管理后台ie假死 无响应的解决方法
  • 原文地址:https://www.cnblogs.com/DilemmaR/p/10908548.html
Copyright © 2011-2022 走看看