JML知识梳理

JML理论基础

关于JML的相关介绍其实课程给出的指导书就已经足够使用了,由于指导书上都有相关知识的梳理,所以这里不花费大量篇幅去书写这部分内容,只是简单提及一些东西。首先是什么是JML,课程进行,其实阅读简单的JML已经没有多大障碍了,但是对于JML的定义这种概念已经忘记的差不多了。JML是用于对Java程序进行规格化设计的一种表示语言,JML是一种行为接口规格语言,基于Larch方法创建。通过使用JML及其相关的支持工具,我们可以基于规格自动构造测试样例,并整合了SMT Solver 等工具以静态方法来检查代买实现对规格的满足情况。目前学习到的JML语言特征只是level0级别,所以只是入门啊(虽然入门就已经能够解决许多问题了)。

JML应用工具链

​ JML拥有丰富的工具库,可以给用户提供JML规范检查,或者是随机测试数据生成测试。现仅举出课程中所涉及的几个.

​ 1.OpenJml来检查JML的规范性

​ 2.使用SMT Solver检查代码等价性

​ 3.使用JMUnitNG生成数据测试代码

​ 4.JMLAutoTest...

部署JMLUnitNG/JMLUnit

针对Graph接口的实现自动生成测试用例, 并结合规格对生成的测试用例和数据进行简要分析。

按照作业梳理自己的架构设计,并特别分析迭代中对架构的重构

第一次作业

第一次的架构其实很清晰了,因为最顶层的架构关系指导书已经指定了,实际上我们实现的是相关方法和细节(都是些比较底层的东西),所以这样主要提一提相关方法和细节的设计实现,顶层架构为将path抽象成一个类,并且在MyPath中实现相关path内的方法,用PathContainer,处理path间的相关操作,并存储所有的path。

path和不同点的存储:采用三HashMap的结构。

private HashMap<Path,Integer> ptoid = new HashMap<>(1024);
private HashMap<Integer,Path> idtop = new HashMap<>(1024);
private HashMap<Integer,Integer> valuepoint = new HashMap<>(102400);

复杂度分析

其中valuepoint中的key是当前路径中所出现的结点id,对应的value是该结点出现的次数。这样对于getDistinctNodeCount()方法,我们只需要输出valuepoint.size()即可。其他查询方法类似。

第二次作业

第二次作业与第一次作业的主要区别在于最短路和连通块上,而其他需求和第一次作业是一样的,所以我的第二次的架构,首先保留了第一次的架构设计(拷贝粘贴到MyGraph,MyPath类消失),在此基础上,在MyGraph类里主要实现了两个操作,一个是维护并查集,一个是用bfs求最短路。由于求最短路的问题,是一个图相关的问题,所以实现了相关的建图函数(邻接表建图)

具体来说,

//新增类 MyGraph , 删除类 MyPath

//新增方法
public int anc(int x)
public void unin(int x, int y)
public void buildufset() // 并查集
public void buildgraph() // 建图
public void buildsp() // 最短路 //bfs求最短路 public void buildspforone(int x)
{
int [] vis = new int [300];
for (int i = 0;i < 300;i++)
{
vis[i] = 0;
}
int [] node = new int [90000];
node[0] = x;
vis[node[0]] = 1;
sp[x][x] = 0;
int l = 0;
int r = 0;
while (l <= r)
{
int nd = node[l];
for (int i = 0;i < edges[nd].size();i++)
{
int nnd = edges[nd].get(i);
if (vis[nnd] == 0)
{
vis[nnd] = 1;
r++;
node[r] = nnd;
sp[x][nnd] = sp[x][nd] + 1;
}
}
l++;
}
}
//新增数据成员
private int [][]sp = new int[300][300]; // 最短路。
private int [] father = new int[300]; // 并查集
private ArrayList<Integer> [] edges = new ArrayList[300]; // 存储边

复杂度分析

由于维护了并查集,所以对于连通块的平均查询是O(1)的,显然可以接受。

对于最短路,由于第二次作业并没有票价之内的问题,所以可以使用bfs来解决无权图的最短路问题,复杂度是O(V+E),由于边数最多为4000,所以也是可以接受的。

对于floyd,由于它的复杂度是稳定在O(n^3)的,所以虽然它好写,我还是没有写,但是事实证明也能过。

第三次作业

第三次作业与第二次作业在需求上有几个主要的不同点:不满意度、票价、换乘、连通块个数。仔细分析可以发现

对于不满意度、票价、换乘都可以抽象成有权图的最短路问题。所以实际上第三次作业与第二次作业的最大区别就是

图有权了,至于连通块个数,由于第二次作业已经实现了并查集,所以直接通过n-times(unin)就得到连通块个数了。

前面说到抽象成有权图的最短路问题,是有一个问题的,如果不拆点,图中的结点同时在多条路径中,也就是说图中结点具有多种性质,朴素的建图是解决不了这种问题的。

然后想到了拆点,结果写完拆点复杂度爆炸,因为极端情况下,拆点使得点数扩大了几十倍,而对于边数更是扩大了上千倍,这种情况下使用现有的算法都面临爆炸的风险,所以当时以为凉凉了...

//拆点 + Dij 思路
public int predij(int x,int y,int model,int num,int ans)
{
for (int i = 0;i < 130;i++)
{
for (int j = 0; j < 50; j++)
{
dis[i][j] = 1070000000;
vis[i][j] = false;
}
}
dis[x][num] = 0;
int w = 0;
Queue<Edge> q = new PriorityQueue<>();
Edge e0 = new Edge(x,x,w,num);
{
q.add(e0);
for (int j = 0;j < namount;j++)
{
Edge ne;
int nn;
do {
ne = q.poll();
nn = ne.getV2();
} while (vis[nn][ne.getPid()]);
vis[nn][ne.getPid()] = true;
if (nn == y)
{
if (ans > dis[nn][ne.getPid()])
{
return dis[nn][ne.getPid()];
}
else { return ans; }
}
for (int k = 0;k < edge[nn].size();k++)
{
costs++;
Node nm = edge[nn].get(k);
w = caculw(nn,nm.getId(),ne.getPid(),nm.getPid(),model);
if (dis[nm.getId()][nm.getPid()] > dis[nn][ne.getPid()] + w)
{
dis[nm.getId()][nm.getPid()] = dis[nn][ne.getPid()] + w;
Edge e = new Edge(nn,nm.getId(),
dis[nm.getId()][nm.getPid()],nm.getPid());
q.add(e);
}
}
}
}
return ans;
}

直到看到了分层图,顿时发现了新世界,通过把path压缩成小图,然后在把各个图进行合并,最终保留下来的图满足,任意两个直接相连的结点一定属于小图,并且该边权值最小。然后通过对每一个path跑一遍最短路,再对合并之后的大图跑一遍最短路就得到了解。

//分层图 + floyd 

//建小图,跑最短路

for (int i = 0;i <= 60;i++)
{
if (ridtop.containsKey(i))
{
Path p = ridtop.get(i);
clearpathedge(pathedge);
nnode.clear();
for (int j = 0;j < p.size() - 1;j++)
{
int s1 = p.getNode(j);
int s2 = p.getNode(j + 1);
if (vtoidx.containsKey(s1) == false) {
vtoidx.put(s1,++nodecnt);
idxtov.put(nodecnt,s1);
}
if (vtoidx.containsKey(s2) == false) {
vtoidx.put(s2,++nodecnt);
idxtov.put(nodecnt,s2);
}
int idx1 = vtoidx.get(s1);
int idx2 = vtoidx.get(s2);
{
pathedge[idx1][idx2] = caculw(idx1,idx2,1,1,model);
pathedge[idx2][idx1] = caculw(idx2,idx1,1,1,model);
if (!nnode.contains(idx1)) { nnode.add(idx1); }
if (!nnode.contains(idx2)) { nnode.add(idx2); }
}
}
addpathedge(model);
}
} //采用朴素的floyd
public void floyd(int [][]a,int type)
{
for (int k = 0;k < 130;k++)
{
if (type == 0 || nnode.contains(k))
{
for (int i = 0; i < 130; i++)
{
for (int j = 0; j < 130; j++)
{
if (a[i][j] > a[i][k] + a[k][j])
{
a[i][j] = a[i][k] + a[k][j];
}
}
}
}
}
}
//最后对大图进行一次然后再跑一次floyd就OK了,^@^

按照作业分析代码实现的bug和修复情况

三次作业中,强测测试和互测测试我都没有丢分(开心..),这里主要是针对提交测评前曾经遇到的bug。

作业一bug分析
  • path的hashmap实现

    path是自定义的对象,所以需要去手动实现它的hashcode和equals方法,这里主要说一下hashcode一定

    要保证能够复现....

  • 判断大小

    判断大小要注意直接减会数值溢出。

作业二bug分析
  • 并查集的实现

    并查集最好实现路径压缩和按秩合并,否则容易被卡成链造成tle.

  • bfs的实现

    bfs注意标记数组,以及bfs只能跑连通块,不连通的点的最短路无限大

  • 标记数组初始化

    由于有重建图操作,以及会跑多次bfs和并查集,所以需要每一次初始化好标记数组的值

作业三bug分析
  • Dijkstra及Floyd的正确书写

    这个算法网上都有,但是由于不熟练,debug弄了很久。

  • 容器内元素是自定义对象时,重写相关方法

    第三次作业中由于自定义了Edge对象,所以使用ArrrayList.contains的时候

    就需要重写equals方法,要不然会按照地址进行查找。

阐述对规格撰写和理解上的心得体会

​ 写规格的速度贼慢,写完之后感觉有语法错误,语法错误de完了,发现还有bug。但是,规格确实比自然语言表意清晰的多,在编写代码的时候也更明白自己到底要做些什么。

​ 具体的规格撰写我的一点小心得就是,从上到下,先思考顶层功能是什么,约束是什么?然后逐层向下思考相同问题。

OO第三单元单元总结的更多相关文章

  1. OO第三单元作业总结

    OO第三单元作业总结--JML 第三单元的主题是JML规格的学习,其中的三次作业也是围绕JML规格的实现所展开的(虽然感觉作业中最难的还是如何正确适用数据结构以及如何正确地对于时间复杂度进行优化). ...

  2. 规格化设计——OO第三单元总结

    规格化设计--OO第三单元总结 一.JML语言理论基础.应用工具链 1.1 JML语言 ​ JML(java modeling language)是一种描述代码行为的语言,包括前置条件.副作用等等.J ...

  3. 【OO学习】OO第三单元作业总结

    [OO学习]OO第三单元作业总结 第三单元,我们学习了JML语言,用来进行形式化设计.本单元包括三次作业,通过给定的JML来实行了一个对路径的管理系统,最后完成了一个地铁系统,来管理不同的线路,求得关 ...

  4. OO第三单元(地铁,JML)单元总结

    OO第三单元(地铁,JML)单元总结 这是我们OO课程的第二个单元,这个单元的主要目的是让我们熟悉并了解JML来是我们具有规格化编程架构的思想.这个单元的主题一开始并不明了,从第一次作业的路径到第二次 ...

  5. OO第三单元——JML之破分大法

    一.Jml总结及应用工具链 总的来说,jml就是对java程序进行规格化设计的一种表示语言,其中最核心的就是规格化,将代码要实现的功能和各项要求与约束不是通过自然语言,而是通过严密的逻辑语言来表达,这 ...

  6. OO第三单元——基于JML的社交网络总结

    OO第三单元--基于JML的社交网络总结 一.JML知识梳理 1)JML的语言基础以及基本语法 JML是用于java程序进行规格化设计的一种表示语言,是一种行为接口规格语言.其为严格的程序设计提供了一 ...

  7. OO第三单元作业——魔教规格

    OO第三单元作业--魔教规格 JML的理论基础和相关工具   JML(Java Modeling Language,Java建模语言),在Java代码种增加了一些符号,这些符号用来标志一个方法是干什么 ...

  8. OO第三单元个人总结

    OO第三单元个人总结 JML理论与基础与应用工具链 JML是什么? Java建模语言(JML)是一种行为接口规范语言,可用于指定Java模块的行为 .它结合了Eiffel的契约设计方法 和Larch ...

  9. 2020 OO 第三单元总结 JML语言

    title: 2020 OO 第三单元总结 date: 2020-05-21 10:10:06 tags: OO categories: 学习 第三单元终于结束了,这是我目前为止最惨的一单元,第十次作 ...

  10. 2020北航OO第三单元总结

    2020北航OO第三单元总结 本单元要求是根据JML规格完善代码,初看是一个简单的代码照搬实现的东西,但最后才发现由于CPU时间的限制,还考察了大量优化策略及数据结构中关于图的知识,是一次非常注重细节 ...

随机推荐

  1. 2019-10-31-VisualStudio-2019-新特性

    title author date CreateTime categories VisualStudio 2019 新特性 lindexi 2019-10-31 08:48:27 +0800 2019 ...

  2. Zabbix--06主动模式和被动模式、低级自动发现、性能优化、

    目录 一. Zabbix主动模式和被动模式 1.克隆模版 2.修改克隆后的模版为主动模式 3.修改监控主机关联的模版为主动模式 4.修改客户端配置文件并重启 5.查看最新数据 二.Zabbix低级自动 ...

  3. Zabbix--05 Grafana、percona、自动发现和自动注册

    目录 一. Grafana自定义图形 1.安装grafana 2.安装并激活zabbix插件 3.数据展示 4.自定义图形仪表盘 5.自定义图形饼图 二. percona模版监控mysql 1.安装p ...

  4. poj3494Largest Submatrix of All 1’s(最大全1子矩阵)

    题目链接:http://poj.org/problem?id=3494 题目大意: 出1个M*N的矩阵M1,里面的元素只有0或1,找出M1的一个子矩阵M2,M2中的元素只有1,并且M2的面积是最大的. ...

  5. Linux虚拟机网络设置问题

    使用的是VM 工作站15 和以前的不一样 没有什么虚拟机网络设置 :打开Edit->Virtual NetWork editor, 选中VMnet8,然后点击NAT Setting按钮,再点击D ...

  6. Python---进阶---文件操作---获取文件夹下所有文件的数量和大小

    一.####编写一个程序,统计当前目录下每个文件类型的文件数 ####思路: - 打开当前的文件夹 - 获取到当前文件夹下面所有的文件 - 处理我们当前的文件夹下面可能有文件夹的情况(也打印出来) - ...

  7. HTML页面滑动到最底部触发事件

    其实基本原理做一个判断,如果 页面总高度  =  视口高度  +  浏览器窗口上边界内容高度 ,那么就是把页面滑动到了最低部,然后执行一个事件. //要触发的事件(自己定义事件的内容) functio ...

  8. Redis实战(十一)Redis面试题

    序言 单线程的redis为什么这么快? 1.纯内存操作不需要进行磁盘的 IO 2.单线程操作避免了频繁上下文切换 3.采用非阻塞的多路I/O复用模型 什么是路I/O复用模型? 核心是监听socket, ...

  9. CSS中的自适应单位vw、vh、vmin、vmax

    1.vw.vh.vmin.vmax各单位的意义 上面的自适应单位可以统称为视口单位. 可以先了解一下视口指的是什么? 在PC端,视口指的是在PC端,指的是浏览器的可视区域:而在移动端,它涉及3个视口: ...

  10. CF D. Labyrinth 01BFS

    由于上下走不限制,所以按照贪心,我们应该尽可能走上下方向. 我们可以开一个双端队列,并认为每次提取队首的时候得到的是到达该点的最优策略.(这个一定是唯一的,因为不可能向右走几格,然后再退回去. ) 那 ...