1.JML规格设计策略

  我三次作业采用的方法都是从性能与存储大小方面考虑。在满足规格的条件下尽量做到运行速度最快,所用空间最小。因为这个单元的作业如果单单只是照着jml规格来翻译的话就失去了意义(因为我太菜了没写测评机啊啊啊啊啊)。

  本单元内容是根据给定的规格实现一个可以实现个人操作,好友关系操作,群组操作,收发消息等的社交网络。我写这个单元的时候,首先是写 Person 这个类, Person是这个单元最基础的类,和其他的类几乎没有牵连,故可以最先完成。每一次进行迭代的时候,我都将两次的规格进行文本对比以找出这所更新的,再来添加这些新的东西。写完 Person后写 Group、 Message等类,这个是只用到 Person的,之后再写 Network,这个是整个代码的核心。最后再完成异常类的编写。

  在具体的类的实现中,我首先是将所有的规格代码都看一遍,以此来选择最合适的容器来设计。在参考了一些同学的方法后,我优化了一些函数,像异常类出现频率高的直接整合成一个函数来调用,以及使用了一些已存在的函数(避免自己造轮子)。

2.测试方法和策略

  这次的测试方法主要还是根据jml规格来。阅读jml的代码,考虑每一句的极限情况,以此来构造边界数据。从理论上来说只要每一步都是正确的,那合起来肯定没问题,但是在实际的测试中发现其实很多情况对单独的一条限制来测试是不够的,因为也许会有其他的语句隐性地限制了,所以还是要阅读一整个方法的规格,综合起来考虑边界情况来测试。不过只要是写的满足了规格,在测试中就不会出错,这个单元重点就在认真阅读jml代码。

  测评机就没写了,自己构造了数据手跑和同学的进行对比。

3.容器的选择和使用

  这个单元的容器主要是 Hashmap。这是基于对速度的考量,而且三次作业的所有类的id都是唯一的,这也是一个很好的使用 Hashmap的条件。怎样选择容器,其实质是基于对jml规格代码的理解。在第一次作业的queryBlockSum函数中,其jml规格代码有用 Person与该 Person之前加入的所有 Person是否有相连关系,这个当时我就认为是和 Person的加入顺序有关的,于是在 Network中 Person这个我使用了Arraylist.直到参考他人的代码时才发现原来可以用 Hashmap,这个函数就是求联通分量的,而且这也是可以通过离散来证明的,果然还是基础学科没学好。

  我使用 Hashmap大多时候是建立一个id和对象的索引,不过在解决联通块问题时,也使用了 <Person, Person> 的哈希键值对,也是为了建立人际关系。另外其实在 Hashmap中,有许多已经造好的轮子,比如merge函数,这个函数实用性非常强,可以大大简化代码,估计性能上没太大的影响。还有就是compute函数,重新计算并返回新的值。我还是对java不太熟悉,感谢给我参考代码的同一个房间的同学!

4.性能问题

  第一次作业第一个性能问题就是每一个查询操作不能遍历,使用 Hashmap就可以解决这个问题。第二个性能问题是对于联通块的计算。在第一作业中,我的iscircle函数直接写的dfs,dfs搜到就立马退出,然后计算联通块也是完全照抄规格来写的,强测没有超时,但是被同房的同学hack超时了,在参考完同学代码后,使用了一个类似找出一个联通块的根的方法,创建了一个<Person, Person>的哈希表,同时定义了一个btc变量来记录联通块的数量。每次有people加入,btc++;每当有addRelation就btc--,同时寻找到根,将people与根相连。这样一来查询联通块直接返回btc,复杂度为O(1)。而iscircle的话直接比较两者的根是否相同即可。

  第二次作业的话主要是对求年龄平均数与标准差的计算,这个也是不能最后遍历求和啥的,得先定义一个变量来存储年龄和,年龄平方和。最后在对规格中给出的表达式来化简求值。主要是要注意精度问题,要严格按照规格来。对于getValueSum这个函数似乎没有好的化简方法,复杂度为O(n^2)。因为可能有删除person的操作,如果也事先记录的话,这个删除也会是O(n^2),并不会有化简。这个函数我选择每次只遍历没有进行比较过的,也只是少了一半的时间。

  第三次作业的话主要是最短路径的查询问题。我是用的是堆优化的Dijkstra算法,并且每查完一次都记录先来了(如果增加了新的关系就作废)。在这条路线上的所有点之间都是最短路径,尽量减少查询的次数。

5.架构设计

  本单元完成了一个基本社交网络的模拟,最基础的类为 Person,该类就是图的节点,之后各种各样的类也是围绕节点展开,节点之间存在联系,即构成边,并赋值为value。同时还存在 Group这种结构可以保存多个 Person,以及相应的数据内容。除此之外还有 Message 的结构可以实现人与人直接,人与组织之间信息的传递。最后 Network类将之前的各类联系和囊括在一起,保存了之前各类存在的信息。

  关于图的维护,主要是对节点和边的增删。主要有addPerson、addRelation等函数。在编写这些函数的时候,需要考虑到自己所有的容器,他们是否需要改变。比如在维护查询联通块的函数中,addPerson需要对联通块数量增1,addRelation则需要对联通块数量减1,同时更新根节点与节点之间的关系。在查询最短路径时,在这两个函数中都要及时维护边与节点的数量关系等等。

JML的更多相关文章

  1. JML契约式设计——第三单元学习小结

    一.前言 本单元作业都是关于JML(Java Modeling Language),JML是一种契约式设计(Design by Contract)的语言,契约式设计的主要目的是希望程序员能够在设计程序 ...

  2. 面向对象设计与构造:JML规格单元作业总结

    面向对象设计与构造:JML规格单元作业总结 第一部分:JML语言理论基础 JML语言是什么:对Java程序进行规格化设计的一种表示语言 使用JML语言有什么好处: 用逻辑严格的规格取代自然语言,照顾马 ...

  3. 2019年北航OO第3单元(JML)总结

    1 JML语言的理论基础及应用工具链 1.1 JML语言 Java建模语言(JML)是一种行为接口规范语言,可用于指定Java模块的行为.它结合了Eiffel的"契约设计(design by ...

  4. OO第三次作业总结(JML)

    第三单元的课题是JML, 即java建模语言.JML是一种描述接的语言.通过前置条件和后置条件,描述一个模块的行为.本单元我们扮演一个项目中的一员,完成自己的一小部分工作,最终实现整个项目.而限制我们 ...

  5. OO第三单元总结——JML

    目录 写在前面 JML理论基础 JML工具链 JMLUnitNG的使用 架构设计 Bug分析 心得体会 写在前面 OO的第三单元学习结束了,本单元我们学习了如何使用JML语言来对我们的程序进行规格化设 ...

  6. OO第三单元总结--根据JML写代码

    一. JML语言 1. 理论基础 首先,JML不是JAVA的一部分,它是一群研究者为JAVA设计的扩展部分,但还没有得到官方的支持.因此,JAVA编译器并不支持JML,所以要想JML起作用,只能采用类 ...

  7. OO第三单元总结——JML规格设计

    • 1.JML语言的理论基础.应用工具链情况 JML(Java Modeling Language)—— java建模语言,是一种行为接口规范语言( behavioral interface spec ...

  8. 2019年北航OO第三单元(JML规格任务)总结

    一.JML简介 1.1 JML与契约式设计 说起JML,就不得不提到契约式设计(Design by Contract).这种设计模式的始祖是1986年的Eiffel语言.它是一种限定了软件中每个元素所 ...

  9. OO_BLOG3_规格化设计(JML学习)

    目录 JML语言学习笔记 理论基础 应用工具链情况 JMLUnit/JMLUnitNG UNIT3 作业分析 作业 3-1 实现两个容器类Path和PathContainer 作业 3-2 实现容器类 ...

  10. 【面向对象】第三单元总结——JML

    梳理JML语言的理论基础.应用工具链情况 JML语言理论基础 JML(Java Modeling Language)是一种行为规范接口语言,通过使用不会被编译的注释形式,和固定关键字的语法,指定Jav ...

随机推荐

  1. TS语法中interface和class的理解

    在TS中interface和后端语言如c#中的概念是不一样的,在TS中interface相当于定义了一种类型,是设置自定义类型的方式,区分与基础类型(number.string等),当定义变量时,就可 ...

  2. 在ubuntu18.04上安装nodejs14

    步骤 1:更新 在 Ubuntu 上运行 apt update 命令以更新软件包库内容数据库. sudo apt update 第 2 步:在 Ubuntu 18.04 上安装 Node.js 14 ...

  3. jquery获取父级容器高度

    //获取浏览器显示区域的高度console.log( $(window).height()); //获取浏览器显示区域的宽度console.log($(window).width()); //获取页面 ...

  4. ubuntu64运行32位程序安装过程

    Ubuntu运行32位程序可以使用如下方法: 第一步: 确认你有一个64位架构的内核 你可以打开终端然后输入: dpkg --print-architecture 你将会看到像下面这样的内容: amd ...

  5. C++ push_back()函数应用

    最近在学习Opencv,用C++写程序,做了一个虚拟画笔的项目,即通过摄像头采集视频图像信息,识别视频中的画笔,并画笔在空中的划痕显示在视频图像上.在进行到划痕显示的,由于视频是实时采集的,检测到的画 ...

  6. SpringBatch生成的DB表SQL

    SQL: -- Autogenerated: do not edit this file DROP TABLE IF EXISTS BATCH_STEP_EXECUTION_CONTEXT; DROP ...

  7. withRouter

    withRouter 可以加工一般组件,让一般组件具备路由组件所特有的api,比如this.props.history withRouter的返回值是一个新组件 import {withRouter} ...

  8. howork7

    " 形式化方法   阅读了解形式化方法形式化方法|形式化方法对软件开发的挑战:历史与发展 根据表达能力,形式化方法可以分为五类: 1)基于模型的方法:通过明确定义状态和操作来建立一个系统模型 ...

  9. antd EditableProTable 组件的简单用法

    首先,antd EditableProTable 组件是在 table组件的基础上又封装了一层,可以实现行更新,删除,增加.只需动动手指,简单配置一下即可. 先下载 EditableProTable ...

  10. LOJ数列分块入门九题(上)

    一转眼,已经有整整一年没有在博客园写博客了.去洛谷写了几篇(How time flys. 最近突然想起其实我不太擅长分块算法,又想起去年暑假有位同学同我提起过LOJ的数列分块九题,说来惭愧,打了这么久 ...