JML理论基础
JML将注释添加到java代码中,确定方法所要执行的内容。有了它,我们就可以描述方法预期的功能,无需考虑实现。同时JML可以在不编写代码的情况下,有效的判断思路是否能够实现,即代码的准确性。同时,JML有助于层次的分化,给每个单元每个类每个方法进行明确的分工。
基本语法:
在这里不多赘述,放个连接。
应用工具链
这里使用的是openjml工具。(在这里感谢伦佬在讨论区的帖子)
样例程序
// demo/Demo.java package demo; public class Demo { /*@ public normal_behaviour @ ensures \result == lhs * rhs; */ public static int compare(int lhs, int rhs) { return lhs * rhs; } public static void main(String[] args) { compare(520541,9547321); } }
以下面的文件树为例
demo
└── Demo.java
执行
java -jar jmlunitng.jar demo/Demo.java
生成一系列java测试文件
使用
javac -cp jmlunitng.jar demo/*.java javac -cp jmlunitng.jar demo/Demo_JML_Data/*.java
对所生成的java文件进行编译
执行
java -jar openjml.jar -rac demo/Demo.java
使用openjml自带的jmlc编译java文件
最后,执行
java -cp jmlunitng.jar demo.Demo_JML_Test
对我们的代码进行测试
最后的结果就是这样的啦
因为代码比较简单,因此这里所评测的临界点在于乘法时越界的情况以及空指针空数组的情况,因此一共报了六个错误。
这种测试在我们进行互测的时候帮助并不是特别大,毕竟可以直接生成数据进行对拍,但是在自测每一个小模块的时候有着无比的快捷性。
第一次作业
类图
思路
第一次作业基本上是让我们了解jml基本语法以及思路,因此所要填写的方法并不是很难,唯一的卡点就是mypathcontainer类中的getdistinctnodecount方法这边不能每次遍历path去进行计算不然会被卡时间,因此我们应该使用一个private变量在每次删减path的时候直接改变它的值,这样就不需要循环遍历了。当然,在pathcontainer中,我们使用hashmap更有利于我们根据id迅速找到所需要的path,同理也可以根据path迅速找到id。
bug及修复
一个很智障的bug,判断equal的时候没有比较size大小直接刚了,导致空指针(如此智障的我)。
五一假期完全不想找bug,不想打评测机,结果房内的活跃度真感人(哭泣),要被扣活跃度分了。
第二次作业
类图
思路
Floyd大法好!第二次作业在第一次的基础上变成对于一个path图的操作,即寻找最短路径。而这次的坑点在于不能每次需要的时候都用一些复杂度很高的算法查询,而要对已经查好的进行保存(因为增删路径的数量很少而查询的数量很多),因此采用Floyd算法,其可以一次找到所有点之间的最短路径。同时把它保存下来,每次查询只需要去里面取就行。删减路径时,更新这个最短路径表。
bug及修复
这次我自己没有遇到bug。
自己打了一个评测机主要是炸tle,互测时炸出了一个人的bug,并不是tle,好像是删路径时候的bug。
第三次作业
类图
思路
讨论区神器wjy所想出的图真的厉害!
这次作业的难点在于算法,我所采用的是对于每个path的路径的边权重中加入换乘的权重,即每个path的任意两点的最小权重(使用Floyd)加上一次换乘权重,所产生的值更新到邻接矩阵(我采用的是三个不同的邻接矩阵,当然设置好不同的权重可以用一到两的矩阵即可完成,我想过两个矩阵完成的情况,但是作业对于这一块的要求不高因此没有使用那种方法)中,如果存在相同的取更小的。这样我们可以继续使用Floyd算出所要的最小不满意度,最少换乘等值,这样所计算出的结果比正常结果多一次换乘的权重,我们需要在最后减去一次换乘的权重即为我们所求。这次作业所要添加的三个方法,最少换乘、最小不满意度和最少票价皆可以采用这样的构图算法。这样的算法可以一次算完所有的点之间的最短路径,在查找时有着无与伦比的优势。当然,还有一些其他方法,比如拆点使用dij等,但是操作复杂度较高,而且经过对比时间并没有改方法快。
本次作业还有一个需要填写的方法,即连通块个数,我使用的是根据已产生的是否连通,遍历删除同一块内的东西,即对于一个节点遍历所有其他与其相连通的点,结束算是一个块,再取没有被连通的点做相同的操作。
bug及修复
本次也手打了一个评测机,主要测试所新加的几个方法和之前的最小路径。不禁吐槽中测真弱,有好多弱智的bug中测没有体现,幸好自己测了,强测并没有炸。
在互测时,同屋有一个人有bug,后来根据他所说是因为contain还是connect那边时间复杂度炸了,但是我的评测机并没有测那一块,因此并没有找到这个bug,写评测机还是需要注意其评测广度。
感想与体会
这个单元主要目的在于让我们理解jml,jml让编程者更加理解架构师所需要的东西,这种语言不同于自然语言,其基本具有唯一性,不会产生理解上的偏差,更有利于在工程中不同人员之间的配合,同时先写JML有助于我们检查代码的正确性,如openjml即可帮助测试边界条件,只要我们在编程的过程中遵循jml中所描述即可。
但这次似乎侧重点偏向于了图算法,所以几次作业更多的时间在于讨论图算法的时间复杂度,讨论区以及大舞台总是有大佬能够帮助我们找到适合的算法,当然我们也需要自己根据大佬所提供的算法进行自己的考虑,从中选择适合自己的。
相比于前几次作业,这一单元在作业的继承上无疑有着巨大的进步,上一次作业所打的代码,在下一次基本拿来使用就行,然不需要进行重构,有些地方甚至对于下一次作业有所帮助。