2022 OO 第三单元个人总结

2022 OO 第三单元个人总结

一、课程内容

本次作业依据课程组提供的JML规格类的接口,自己实现能达到要求的类。

1. 框架设计

我的框架与官方包相同,并没有进行一些额外的设计。

 

 

2. 算法性能

本次作业的难点我认为有两方面,一个是对于JML规格的阅读,另一个就是对于算法的选择。

对于测试限制,我们要避免出现O(n2)的时间复杂度,尽可能都限制在O(nlogn)

维护变量代替直接查询

对于一些变量,如ageSumvalueSum等变量,如果每次都查询都进行计算,那该请求的时间复杂度将会达到O(n2),导致TLE,所以我们选择使用在Group中创建一个valueSum变量,每次addPerson, deletePerson, addRelation时对其进行维护,以保证每次查询的时间复杂度为O(1)

并查集

对于isCircle算法,要求寻找两点是否连接,也就是两点间是否有通路。采用并查在每次addPerson, addRelation时进行维护,使该复杂度在维护时为O(n),查询时为O(1)

堆优化的prim算法

对于sendIndirectMessage方法,需要使用dijkstra图算法,而普通的dijkstra算法的时间复杂度为O(n2),采用堆优化的dijkstra算法可以将复杂度降为O(mlogn)

容器选择

在本单元中,大量使用了HashMap容器来储存信息,以保证快速搜索。

另外对于图的信息储存,使用三个ArrayList来存储图的所有边。

3. 测试方法

由于指令数量、形式有限,所以本单元我首先采用形式化测试,对于每个指令的不同情况进行测试正确性,之后通过随机生成指令与同学对拍测试。

我出现的主要问题包括:

  • 使用dfs算法实现isCircle复杂度为O(n3),导致CTLE;

  • 对于ageMean等函数没有考虑到除数为了0的情况,归根结底时对于JML规格的阅读不熟悉。

二、拓展思考

假设出现了几种不同的Person

  • Advertiser:持续向外发送产品广告

  • Producer:产品生产商,通过Advertiser来销售产品

  • Customer:消费者,会关注广告并选择和自己偏好匹配的产品来购买 -- 所谓购买,就是直接通过Advertiser给相应Producer发一个购买消息

  • Person:吃瓜群众,不发广告,不买东西,不卖东西

如此Network可以支持市场营销,并能查询某种商品的销售额和销售路径等 请讨论如何对Network扩展,给出相关接口方法,并选择3个核心业务功能的接口方法撰写JML规格

相关接口

可见,Advertiser, Producer, Customer均继承自Person类。

对于CustomerProducer之间的购买行为,Person本身具有Money属性,可以通过RedEnvelopeMessage来实现。

对于CustomerAdvertiser之间的传递产品信息的行为,以及ProducerCustomer销售产品的行为,可以通过NoticeMessage来实现。

注意,此时忽略了Customer应支付给Advertiser推销金钱,但也可通过RedEnvelopeMessage来实现。

 public interface Producer extends Person {
     //让advertiserId推销noticeMessage
     public void publishAdvertisement(int advertiserId, NoticeMessage noticeMessage) throws PersonIdNotFountException;
 }
 
 public interface Advertiser extends Person {
     //推销noticeMessage,只发type == 1
     public void advertise(NoticeMessage noticeMessage);
 }
 
 public interface Customer extends Person {
     //发送redEnvelopeMessage
     public void purchase(RedEnvelopeMessage redEnvelopeMessage);
 }

JML规格

 /*@ public normal_behavior
   @ requires (\exists int i; 0 <= i && i < advertisers.length; advertisers[i].getId() == advertiserId)
   @ assignable advertisers[*].messages
   @ ensures (\forall int i; 0 <=i && i < advertisers.length && advertiserId != advertisers[i].getId();
   @ advertisers[i].messages == \old(advertisers[i].messages));
   @ ensures (\forall int i; 0 <=i && i < advertisers.length && advertiserId == advertisers[i].getId();
   @ advertisers[i].messages.length == \old(advertisers[i].messages.length) + 1);
   @ ensures (\forall int i; 0 <=i && i < advertisers.length && advertiserId == advertisers[i].getId();
   @ advertisers[i].messages[0] == noticeMessage);
   @ ensures (\forall int i; 0 <=i && i < advertisers.length && advertiserId == advertisers[i].getId();
   @ \forall(int j; 0 <= j && j < \old(advertisers[i].messages.length);
   @ advertisers[i].messages[j + 1] == \old(advertisers[i].messages)[j]));
   @ public exceptional_behavior
   @ signals (PersonIdNotFountException e) ! (\exists int i; 0 <= i && i < advertisers.length;
   @ advertisers[i].getId() == advertiserId)
   @*/
  public void publishAdvertisement(int advertiserId, NoticeMessage noticeMessage) throws PersonIdNotFountException;
 
 /*@ public normal_behavior
   @ assignable noticeMessage.getGroup.people[*].messages
   @ ensures (\forall int i; 0 <=i && i < noticeMessage.getGroup.people.length;
   @ noticeMessage.getGroup.people[i].messages.length
   @ == \old(noticeMessage.getGroup.people[i].messages.length) + 1);
   @ ensures (\forall int i; 0 <=i && i < noticeMessage.getGroup.people.length;
   @ noticeMessage.getGroup.people[i].messages[0] == noticeMessage);
   @ ensures (\forall int i; 0 <=i && i < noticeMessage.getGroup.people.length
   @ \forall(int j; 0 <= j && j < \old(noticeMessage.getGroup.people[i].messages.length);
   @ noticeMessage.getGroup.people[i].messages[j + 1] ==
   @ \old(noticeMessage.getGroup.people[i].messages)[j]));
   @*/
  public void advertise(NoticeMessage noticeMessage);
 
 /*@ public normal_behavior
   @ assignable producer[*].messages
   @ ensures (\forall int i; 0 <=i && i < producer.length && redEnvelopeMessage.getPerson2.getId() !=
   @ producer[i].getId(); producer[i].messages == \old(producer[i].messages));
   @ ensures (\forall int i; 0 <=i && i < advertisers.length && redEnvelopeMessage.getPerson2.getId() ==
   @ producer[i].getId(); producer[i].messages.length ==\old(producer[i].messages.length) + 1);
   @ ensures (\forall int i; 0 <=i && i < producer.length && redEnvelopeMessage.getPerson2.getId() ==
   @ producer[i].getId(); producer[i].messages[0] == redEnvelopeMessage);
   @ ensures (\forall int i; 0 <=i && i < producer.length && redEnvelopeMessage.getPerson2.getId() ==
   @ producer[i].getId(); \forall(int j; 0 <= j && j < \old(producer[i].messages.length);
   @ producer[i].messages[j + 1] == \old(producer[i].messages)[j]));
   @*/
  public void purchase(RedEnvelopeMessage redEnvelopeMessage);

 

三、个人感悟

本单元的学习,从知识上让我学会了阅读JML规格,对于JML规格的实现有了基本的了解。对于JML规格的优缺点有了一定的思考,其在复杂函数的规格限制上具有简洁性,但对于另一些算法就会显得臃肿。

另外在算法层面,本次作业让我了解了许多减少复杂度的方法,对于维护变量来替代历次计算的思想,我认为时很重要的收获。

 
posted @ 2022-05-31 23:21  iLoveFox  阅读(25)  评论(0编辑  收藏  举报