oo第三单元总结

oo第三单元总结

一、总体概述

本单元的作业就是在解读JML规格下完成模拟社交网络以及异常的处理。主要任务就是理解JML,所以相对做起来比较容易。同时要注意JML是一种规格化的语言,只要在完成所描述的任务的条件下、并没有限制所使用的容器算法等。同时也要掌握一些基本的图算法,比如最短路径最小生成树算法。同时要注意性能的影响,有些指令按照“正常的思路”写有的复杂度甚至能到n5或者n6,1w组数据根本受不了。

同时在这一单元尽量避免arraylist,普通数组的使用,尽量使用hashset等存储结构。(不然说不定莫名其妙复杂度就多了一个数量级

二、作业分析

第九次作业

第九次作业主要重写了三个类,MyPerson、MyGroup以及Mynetwork,同时有6个异常处理操作。MyPerson就是相当于社交网络中的用户,MyGroup就相当于是一个群,而Mynetwork最为复杂,相当于是记录了所有用户的信息,可以访问所有的用户并得到他们之间的关系。具体细节不在赘述。

此处有一个函数isCircle,用于判断两个人之间有没有”间接联系”,简单的来说就是一个人通过他的好友,他的好友在找好友的好友,能联系到另一个人。

此处可以采用并查集的知识,大大降低复杂度。在addrelation的时候首先判断这两个人是否已经在同一个树里了(parent节点相同),如果没有那么就更新,只需要将其中一个的根节点设置成另一个跟节点,存在的话就不必更新。每次查找之后将父节点设置成根节点,进行路径压缩。从而将iscircle的复杂度降至o1。

public int find(int id) {
   if (id == pa.get(id)) {
       return id;
  } else {
       pa.replace(id, find(pa.get(id)));//路径压缩
       return find(pa.get(id));
  }
}
第十次作业

和第九次作业明显的区别就是JML的描述量增加,有一个关于最小生成树的描述,queryLeatConnection,此数我是采用了Prim算法,复杂度是o(n2)。我的prim写的非常拉,因为我用数组实现了(就是大一那个c代码)。但是还是考虑了一下降低复杂度的方法。就是在考虑图的存储,person的数量3000左右,而我们需要的其实是与查询id相关的人,而第九次作业分析了iscircle的复杂度用并查集实现为1。所以在建图的时候可以采用find找到与id的根节点相同的人存储。会在一定程度上降低复杂度。加上对最小生成树查询指令的限制,应该是没有超时的。

但是意想不到的qgvs超时了。。。querygroupvaluesum,由于用arraylist存储复杂度一不小心上on4了。强测寄了。可以采用“分散复杂度的方式解决”,(将复杂度分散到各个角落,合起来的复杂度就不会很高)。比如在group的addperson的时候就遍历group中的person,如果islinked就加上queryvalue更新返回值,同理在delperson的时候如果islinked就减掉。同时在addrelation的时候如果两个人在一个group中那么就意味着他们之间加入了queryvalue,需要更新。这样将复杂度分散,qgvs的复杂度变成1。addperson(1->n2),delperson(1->n2),以及addrelation(n->n2)。

第十一次作业

第十一次作业加入了很多消息的种类,发红包、表情啊之类的,加入了几个新的异常。

就是求最短路径的时候容易超时。开始用普通的dist,跑了一组数据cpu用时40s,果断放弃。采用堆优化的dist。首先是图的维护。采用了HashMap<Integer, HashMap<Integer, HashMap<Integer, Integer>>> matrix;维护了所有的边。第一个integer代表一个树的根节点,它所对应的hashmap就是这个树中所有的节点。这个hashmap的key就是每个节点所对应的id,然后下一个hashmap中存储的就是这个节点和其他节点所对应的queryvalue。实现了边的存储。

而dsit复杂度体现在他需要一个比较的过程,即遍历已选好的顶点的相邻的所有边,找到最小的边。而这个比较我们可以采用堆进行优化,将复杂度降至nlogn。具体来说就是用java中已经存在的数据结构priorityqueue(堆实现,就不用我们再花时间写堆了),重写对应的compareTo方法,他会在add方法进行的过程中自动排序。使得我们poll出来是最小的。将找最小值复杂度由n降至logn。

bug:虽然但是,我的money计算错了,手滑将一个人发红包一个人收红包写成两个人都发红包了,不可思议的是强测对了。(说明大部分时候人们还不太喜欢发红包

三、bug分析

这个单元bug出现就比较零散。卡时间复杂度的话,必须有大量的数据堆积。同时也会有很多对jml理解出现的失误(比如括号的位置)。建议写评测机进行数据的投喂。

四、Network拓展

/*@ public instance model non_null Advertiser[] advertisers;
 @ public instance model non_null Advertise[] advertise;
 @*/
Advertiser
   /*@ public instance model int Advertiserid;
   @ public instance model Advertise newadvertise;
   @*/
/*@ public normal_behavior
 @ requires containsAdvertiserid(Advertiserid) && containsId(personid) && getperson(Advertiseid).isLinked(personid);
 @ assignable getperson(personid).getadvertise;
 @ ensures getperson(personid).getadvertise.size() = \old(getperson(personid).getadvertise.size()) + 1;
 @ ensures (\forall int i; 0 <= i && i < \old(getperson(personid).getadvertise.size()); getperson(personid).getadvertise[i+1] == \old(getperson(personid).getadvertise[i]));
 @ ensures (getperon(personid).getadvertise[0] == newadvertise);
 @ also
 @ public exception_behavior
 @ assignable nothing
 @ requires !containsAdvertiseid(Advertiseod) || !containsid(personid) || !getperson(Advertiseid).isLinked(getperson(personid));
 @ signals (PersonIdNotFoundException e) !containsAdvertiseid(Advertiseod);
 @ signals (PersonIdNotFoundException e) !containsid(personid);
 @ signals (RelarionNotFoundException e) !getperson(Advertiseid).isLinked(getperson(personid));
 @*/
public void sendadvertise(int Advertiserid, int personid) throws PersonIdNotFoundException, RelarionNotFoundException;

/*@ public normal_behavior
 @ requires containspersonid(personid)
 @ assignable getcustomer(personid).itsproducts;
 @ ensures (\forall int i; i >= 0 && i <= advertise.size(); getcustomer(personid).itsproducts.add(advertise2produce(advertise[i])));
 @ ensures itsproducts.size() == \old(itsproducts.size()) + advertise.size();
 @ ensures advertise.size() == 0;
 @ public exception_behavior
 @ assignable nothing
 @ requires !containspersonid(personid)
 @ signals (PersonIdNotFoundException e) !containspersonid(personid);
 @*/
public void sendmessage2buy(int personid) throws PersonIdNotFoundException;

Product
   /*@ public instance model int proid;
  public instance model int value;
   @*/
/*@ public normal_behavior
 @ requires containsproid(proid);
 @ ensures \result == getpro(proid).getvalue;
 @ also
 @ public exception_behavior
 @ requires !containsproid(proid);
 @ signals (ProductionidNotFoundException e) !containsproid(proid);
public /*pure*/ int getvalueodproduction(int proid) throws ProductionidNotFoundException;

 

五、本单元总结

本单元重在JML类图的理解,相对来说代码实现并没有很难,但是会出现各种奇奇怪怪的bug。在时间复杂度上尽量降到n2以下,不然数据量过大很容易挂掉。同时要考虑合适的存储结构,比如边的存储。然后就是注意一下ArrayList之类的方法,比如contains之类的就会提高你的复杂度。然后就是评测机的重要性,有些bug手搓是可以的,小数据即可,但是也有些很大量数据才能体现。通过对拍的方式进行bug验证也是不错的方式。总体来说本单元还算顺利。

六、鸣谢

感谢br、xh、ljc哥哥的帮助!给我提供了很多思路和bug的修复。尤其感谢xhgg的评测!

 



posted @ 2022-06-03 16:13  tianrunrun  阅读(32)  评论(0编辑  收藏  举报