OO_Unit3_blog

OO第三单元博客

1 测试方法

第三单元中我的测试主要分为两种:

  • 基础的操作,我手动构造了若干基础样例进行了基本测试。

  • 对于时间复杂度较高的若干方法,通过半自动的方法构造数据进行对拍,包括:

    • qbs求连通分支总数。

    • qlc求最小生成树,测试Prim算法的时间和正确性。

    • qgvs中涉及n^2算法的时间估计。

    • sid测试dijkstra算法的时间和正确性。

具体运行时,可以使用linux的time指令,将time加在运行指令之前。不过对于我的电脑,直接用git bash运行user time值会出问题,需要子在wsl或者虚拟机下使用time指令才可以。

time cat input.txt | java -jar HW-11-CCY.jar > out.txt

2 架构设计与分析

第三单元中,关于每个类对应的接口以及抽象异常类的结构已经给出。我的架构完全仿造接口,并没有搭建新的类。

2.1 第九次作业

设置三个类MyPersonMyGroupMyNetWork分别继承对应接口。按照jml实现各个方法,并没有增加新的类。

这次作业中,每个类只维护自己的基本信息:

  • MyPerson类维护所有自己有关系的人。

  • MyGroup维护组内的包含的人。

  • MyNetWork维护包含所有的人和组。

2.2 第十次作业

在上一次基础上引入了MyMessage类,与MyPersonMyGroup两个类进行交互。新增加的维护信息有:

  • MyPerson类新维护自己的moneysocialValue字段,和其目前拥有的Message容器。

  • MyGroup类新维护变量valueSum,代表组内所有人的value之和。

  • MyNetWork类维护其包含的所有Message

2.3 第十一次作业

在上一次基础上,将MyMessage类细化,引入了MyEmojiMessageMyRedEnvelopeMessageMyNoticeMessage类继承MyMessage。新增加的维护信息有:

  • MyNetWork新维护一个所有emoji的出现频率列表。

2.4 图的构建与维护

在社交网络NetWork中,Person类作为点,Group类为点集。而边的关系则抽象在了Person类的字段中,整个关系网络图的组织结构类似于邻接表。

对于图主要操作有以下几个:

  • isCircle / qureyBlockSum,查询两点是否连通/求连通分支数。我采用了复杂度O(n)的dfs剪枝算法,初次调用时新开一个访问标记数组,递归调用时维护即可。

  • queryLeastConnection我采用Prim算法,我将邻接表转换为邻接矩阵进行简化。

  • sendIndirectMessage 采用堆优化的dijkstra方法,可以直接使用邻接表的信息。

因此在函数外,这些函数只会用到addRelation时维护的信息,无需额外维护图的信息。

3 性能问题与修复情况

性能优化采取了这些措施:

  • 对于jml语言中表述为数组的类型,全部使用了HashMap替代,以存放容器。键值为对象对应的id值,元素值为存储的对象。这样可以实现O(1)的查找。

  • 对于qgvs指令调用Group类中的getValueSum()方法,如果每次调用时去遍历Group内的Person,而Person再去遍历自身有联系的Person。则算法复杂度会到O(n^2)

    解决方法:在Group类中维护这一返回值。在每次调用addRelationaddPersondelPerson三个方法时更新值。将对一次O(n^2)复杂度方法的调用分摊到多次O(n)的维护中,避免了TLE的问题。

  • 对于求最短路的dijkstra算法,在更新剩余边距离时维护其构成的有限队列,将复杂度降至mlog(n),其中m为边数,n为点数。

4 NetWork扩展

Advertiser, Producer, Customer分别继承Person类。

选择三个方法进行具体的实现:

  • 向某个特定顾客发送广告

  • 向某个特定生产商发送广告

  • 查询特定生产商的总销售额

/*@public normal_behavior
 @requires containsCustomer(customerIds) && containAdvertiser(advId) &&
 @(\forall int i; 0 <= i && i < getCustomer(customerIds).advertisers.length;
 @         !getCustomer(customerId).advertiers[i].equals(getAdvertiser(advId)));
 @ assignable getCustomer(customerId).advertiers;
 @ ensures getCustomer(customerId).advertiers.length ==
 @\old(getCustomer(customerId).advertiers.length) + 1;
 @ ensures (\forall int i; 0 <= i && i <\old(getCustomer(customerId).advertiers.length);
 @       (\exists int j; 0 <= j && j <\old(getCustomer(customerId).advertiers.length);
 @getCustomer(customerId).advertiers[j] ==
 @(\old(getCustomer(customerId).advertiers[i]))));
 @ensures (\exists int i; 0 <= i && i < getCustomer(customerId).advertiers.length;
 @getCustomer(customerId).advertiers[i] == getAdvertiser(advId));
 @ also exceptional_behavior
 @ signals (CustomerIdNotFoundException e) !containsCustomer(customerId);
 @ signals (advIdNotFoundException e) containsCustomer(customerId) &&
 @!containAdvertiser(advId);
 @ signals (EqualAdvertiserException e) containsCustomer(customerId) &&
 @containAdvertiser(advId) &&
 @(\exists int i; 0 <= i && i < getCustomer(customerId).advertisers.length;
 @         getCustomer(customerId).advertiers[i].equals(getAdvertiser(advId)));
 @ */
 public void advertiseCustomer(int advId, int customerId) throws CustomerIdNotFoundException, AdertiserIdNotFoundException, EqualAdvertiserException;


/*@public normal_behavior
 @requires containsProducer(producerId) && containAdvertiser(advId) &&
 @(\forall int i; 0 <= i && i < getAdvertiser(advId).producers.length;
 @         !getAdvertiser(advId).producers[i].equals(getProducer(producerId)));
 @ assignable getAdvertiser(advId).producers;
 @ ensures getAdvertiser(advId).producers.length ==
 @\old(getAdvertiser(advId).producers.length) + 1;
 @ ensures (\forall int i; 0 <= i && i < \old(getAdvertiser(advId).producers.length);
 @         (\exists int j; 0 <= j && j < getAdvertiser(advId).producers.length;
 @getAdvertiser(advId).producers[j] ==
 @(\old(getAdvertiser(advId).producers[i]))));
 @ ensures (\exists int i; 0 <= i && i < getAdvertiser(advId).producers.length;
 @getAdvertiser(advId).producers[i] == getProducer(producerId));
 @also
 @ public exceptional_behavior
 @ signals (ProducerIdNotFoundException e) !containsProducer(producerId);
 @ signals (advIdNotFoundException e) containsProducer(producerId) &&
 @!containAdvertiser(advId);
 @ signals (EqualProducerException e) containsProducer(producerId) &&
 @containAdvertiser(advId) &&
 @(\exists int i; 0 <= i && i < getAdvertiser(advId).producers.length;
 @         getAdvertiser(advId).producers[i].equals(getProducer(producerId)));
 @ */
public void advertiseProducer(int advId, int producerId) throws ProducerIdNotFoundException, advIdNotFoundException, EqualProducerException;

/*@public normal_behavior
 @requires containsProducer(producerId);
 @assignable getProducer(producerId).products;
 @ensure \result == (\sum int; 0 <= i && i < getProducer(producerId).products.size;
 @getProducer(producerId).products[i].sale);
 @also
 @public exceptional_behavior
 @signals(ProducerNotFoundException e) !containsProducer(producerId);
 @ */
public /* pure */void getSaleSum(int producerId) throws ProducerNotFoundException;

5 第三单元学习体会

第三单元难度较前两单元有所下降,因此通过中测需要的时间明显降低。但是由于我并没有投入太多精力开发评测机,只对一部分极端情况和基础情况进行了针对性的构造,在数据构造和生成这方面的能力还有待提高。

在这一单元中,我初步学习了jml语言的语法,体会到了契约式编程带来的便捷。而在代码具体编写中,我还复习了离散数学中图论的知识和数据结构中的图相关的编程知识。这些在我日后的学习和工作中会很有帮助。

posted on 2022-06-06 13:00  cccvs  阅读(51)  评论(0编辑  收藏  举报