OO_Unit3_blog
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 第九次作业
设置三个类MyPerson
,MyGroup
,MyNetWork
分别继承对应接口。按照jml实现各个方法,并没有增加新的类。
这次作业中,每个类只维护自己的基本信息:
-
MyPerson
类维护所有自己有关系的人。 -
MyGroup
维护组内的包含的人。 -
MyNetWork
维护包含所有的人和组。
2.2 第十次作业
在上一次基础上引入了MyMessage
类,与MyPerson
、MyGroup
两个类进行交互。新增加的维护信息有:
-
MyPerson
类新维护自己的money
,socialValue
字段,和其目前拥有的Message
容器。 -
MyGroup
类新维护变量valueSum
,代表组内所有人的value
之和。 -
MyNetWork
类维护其包含的所有Message
。
2.3 第十一次作业
在上一次基础上,将MyMessage
类细化,引入了MyEmojiMessage
,MyRedEnvelopeMessage
,MyNoticeMessage
类继承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
类中维护这一返回值。在每次调用addRelation
,addPerson
,delPerson
三个方法时更新值。将对一次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 第三单元学习体会
第三单元难度较前两单元有所下降,因此通过中测需要的时间明显降低。但是由于我并没有投入太多精力开发评测机,只对一部分极端情况和基础情况进行了针对性的构造,在数据构造和生成这方面的能力还有待提高。