一、测试数据准备
JML规格可以有效避免自然语言的表达不准的问题。
JML规格中的前置条件至关重要,本单元中的前置条件会包括许多异常条件,所以在构造测试数据的时候应该完全覆盖各种条件,但是对于不同的测试点应该略有不同的侧重,有时侧重正确操作的测试,有时侧重异常抛出的测试。在本单元中我和三位同学进行了对拍测试,对拍测试可以有效地找到bug,提高测试点的正确率。
二、架构设计
合适的容器
第九次作业我采用Arraylist容器来进行数据存储,虽然数据查找的时候性能为O(n),但是并没有导致CTLE的情况出现,所以我也就没有修改成hashmap容器,第十次作业我原本采用Arraylist但是发生了CTLE的问题,在bug修复的时候我把数据统一放进了hashmap中,第十一次作业中只出现了未实现堆优化而导致CTLE的情况。
选择合适的容器并按照JML规格进行搭建基本上就不会出现什么bug
三、性能问题
性能优化
并查集
private HashMap<Integer, Integer> fa;
private void merge(int x, int y, HashMap<Integer, Integer> fa) {
int fx = find(x, fa);
int fy = find(y, fa);
if (fx != fy) {
fa.put(fx, fy);
}
}
private boolean judge(int x, int y, HashMap<Integer, Integer> fa) {
return find(x, fa) == find(y, fa);
}
private int find(int x, HashMap<Integer, Integer> fa) {
if (fa.get(x) == x) {
return x;
} else {
return find(fa.get(x), fa);
}
}
第一次作业中的qci,若不采用并查集,前者的时间复杂度为O(n),后者更是由于调用前者,时间复杂度可以达到O(n^3);而采用并查集后,则可以将前者降为接近O(1),后者则为O(n),效果显著。
路径压缩,可以有效降低复杂度。
qbs指令我采用的是维护一个blocksum变量,大大缩短时间复杂度。
堆优化
通过PriorityQueue容器实现堆优化,可避免查找最小导致耗费时间复杂度.
Queue<Person> priorityqueue = new PriorityQueue<>();
priorityqueue.poll();
neighbourNodesArray = min.getAcquaintance();
neighbourLengthArray = min.getValue();
int temp = min.getLength();
for (int i = 0; i < neighbourNodesArray.size(); i++) {
tempPerson = (MyPerson) neighbourNodesArray.get(i);
newLength = temp + neighbourLengthArray.get(i);
tempPerson.setLength(newLength);
priorityqueue.add(tempPerson);
}
while (!priorityqueue.isEmpty()) {
min = (MyPerson) priorityqueue.poll();
if (min.isFind()) {
continue;
}
min.setFind(true);
neighbourNodesArray = min.getAcquaintance();
neighbourLengthArray = min.getValue();
temp = min.getLength();
for (int i = 0; i < neighbourNodesArray.size(); i++) {
tempPerson = (MyPerson) neighbourNodesArray.get(i);
oldLength = tempPerson.getLength();
newLength = temp + neighbourLengthArray.get(i);
if (oldLength > newLength) {
tempPerson.setLength(newLength);
priorityqueue.add(tempPerson);
}
}
}
四、扩展
假设出现了几种不同的Person
-
Advertiser:持续向外发送产品广告
-
Producer:产品生产商,通过Advertiser来销售产品
-
Customer:消费者,会关注广告并选择和自己偏好匹配的产品来购买 -- 所谓购买,就是直接通过Advertiser给相应Producer发一个购买消息
-
Person:吃瓜群众,不发广告,不买东西,不卖东西
如此Network可以支持市场营销,并能查询某种商品的销售额和销售路径等 请讨论如何对Network扩展,给出相关接口方法,并选择3个核心业务功能的接口方法撰写JML规格(借鉴所总结的JML规格模式)
/*@ public normal_behavior
@ requires !(\exists int i; 0 <= i && i < messages.length; messages[i].equals(message)) && (message.getPerson1() instanceof Advertiser);
@ assignable messages;
@ ensures (\forall int i; 0 <= i && i < \old(messages.length);
@ (\exists int j; 0 <= j && j < messages.length; messages[j].equals(\old(messages[i]))));
@ ensures (\exists int i; 0 <= i && i < messages.length; messages[i].equals(message));
@ ensures messages.length == \old(messages.length) + 1;
@ also
@ public exceptional_behavior
@ signals (AdvertiserNotFoundException e)
@ !(\exists int i; 0 <= i && i < messages.length; messages[i].equals(message))
@ && !(messages[i].getPerson1() instanceof Advertiser);
@*/
public void addAdvertise(/*@ non_null @*/Message message) throws AdvertiserNotFoundException;
/* @ public normal_behavior
@ requires (\exists int i; 0 <= i && i < list.length; list[i] == product)
@ assignable nothing
@ ensures \result = (\sum int i; 0 <= i && i < people.length;
@ (\sum int j; 0 <= j && j < people[i].poccess && people[i].poccess == product; 1));
@ also
@ public exceptional_behavior
@ signals (ProductNotFoundException e) !(\exists int i; 0 <= i && i < list.length; list[i] == product)
@*/
public int trade(/*@ non_null @*/ Product product) throws ProductNotFoundException
/*@ public normal_behavior
@ assignable getPerson(personId1).money, getTrader(personId2).getProduct(productId)
@ requires contains(personId1) && contains(personId2);
@ requires containsProduct(productId);
@ requires containsTrader(personId2);
@ ensures getPerson(personId1).money = \old(getPerson(personId1).money) - getProduct(productId).getValue;
@ ensures getTrader(personId2).getProduct(productId) = \old(getTrader(personId2).getProduct(productId)) - 1;
@ also
@ public exceptional_behavior
@ signals (PeronIdNotFoundException) !contains(personId1);
@ also
@ public exceptional_behavior
@ signals (PeronIdNotFoundException) !contains(personId2);
@ also
@ public exceptional_behavior
@ signals (TraderIdNotFoundException) !containsTrader(personId2);
@ also
@ public exceptional_behavior
@ signals (ProductIdNotFoundException) !containsProduct(productId);
@*/
public void purchase(int personId1, int personId2, int productId) throws PeronIdNotFoundException, TraderIdNotFoundException, ProductIdNotFoundException;
五、学习体会