OO_第三单元总结
OO_第三单元总结
一、测试
- 对于性能测试构造了菊花图,完全图等数据测试程序性能
- 对于正确性。随机生成数据,和同学对拍
二、架构设计
图模型构建和维护策略
- 对于qbs和qci指令我使用的并查集维护,并进行路径压缩,复杂度为 O(nα(n))
- 对于qlc指令,我用的Kruskal算法计算最小生成树,并用并查集优化。每次查询时对在一个联通块的点单独建图计算,复杂度为 O(mlogm)
this.people = people;
this.edges = new ArrayList<>();
father = new int[17000];
indHashMap = new HashMap<>();
for (int i = 0; i < people.size(); i += 1) {
father[i] = i;
indHashMap.put(people.get(i).getId(), i);
}
for (Person person: people) {
ArrayList<Person> acquaintance = ((MyPerson) person).getAcquaintance();
ArrayList<Integer> value = ((MyPerson) person).getValue();
for (int i = 0; i < value.toArray().length; i += 1) {
if (indHashMap.containsKey(acquaintance.get(i).getId()) == false) {
continue;
}
Edge edge = new Edge();
edge.setEdge(person.getId(), acquaintance.get(i).getId(), value.get(i));
edges.add(edge);
}
}
edges.sort(new SortByIndex());
blockSum = people.size();
}
- 对于sim指令,我用堆优化的迪杰斯特拉算法进行计算,复杂度为 O((m+n)logn)
Comparator<SPathNode> queueComparator = new PersonComparator();
PriorityQueue<SPathNode> priorityQueue = new PriorityQueue<>(2550, queueComparator);
HashMap<Integer, Integer> shortestDis = new HashMap<>();
shortestDis.put(stId, 0);
SPathNode stNode = new SPathNode(stId, 0);
priorityQueue.add(stNode);
int result = -1;
while (true) {
if (priorityQueue.isEmpty()) {
break;
}
SPathNode nowNode = priorityQueue.remove();
if (nowNode.getPersonId() == endId) {
if (result == -1) {
result = nowNode.getDistance();
}
else {
if (result > nowNode.getDistance()) {
result = nowNode.getDistance();
}
}
}
if (nowNode.getDistance() > shortestDis.get(nowNode.getPersonId())) {
continue;
}
ArrayList<Integer> value = ((MyPerson) getPerson(nowNode.getPersonId())).getValue();
ArrayList<Person> acquaintance =
((MyPerson) getPerson(nowNode.getPersonId())).getAcquaintance();
for (int i = 0; i < acquaintance.size(); i += 1) {
int toId = acquaintance.get(i).getId();
int newDis = nowNode.getDistance() + value.get(i);
if (!shortestDis.containsKey(toId)) {
shortestDis.put(toId, newDis);
SPathNode addNode = new SPathNode(toId, newDis);
priorityQueue.add(addNode);
}
else {
if (shortestDis.get(toId) > newDis) {
shortestDis.replace(toId, newDis);
SPathNode addNode = new SPathNode(toId, newDis);
priorityQueue.add(addNode);
}
}
}
}
return result;
}
三、问题与修复
- 在阅读qgva的规格时把
@ ensures \result == (people.length == 0? 0 : ((\sum int i; 0 <= i && i < people.length;
@ (people[i].getAge() - getAgeMean()) * (people[i].getAge() - getAgeMean())) /
@ people.length));
的people.length前的/位置搞错,本应是先求和后除法,写成了先除法后求和
- 性能上获取network中的人时。一开始我是遍历所有的人,这样复杂度较高为O(n)的,有点点会TLE。而后改成了Hashmap做映射。
四、Network进行扩展
- Advertiser:持续向外发送产品广告。方法addProductInfoMessage
/*@ public normal_behavior
@ requires !(\exists int i; 0 <= i && i < messages.length; messages[i].equals(message)));
@ assignable messages, countOfProducts;
@ ensures messages.length == \old(messages.length) + 1;
@ 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 countOfProducts.get(products) == \old(countOfProducts.get(products)) + 1;
@ also
@ public exceptional_behavior
@ signals (EqualMessageIdException e) (\exists int i; 0 <= i && i < messages.length;
@ messages[i].equals(message));
@*/
public void addProductInfoMessage(Product product);
- Producer:产品生产商,通过Advertiser来销售产品。方法:sendAdvertisement
/*@ public normal_behavior
@ requires containsMessage(id) && countOfProducts.get(product) != 0;
@ assignable messages, countOfProducts, advertise.advertiserProduct;
@ ensures !containsMessage(id) && messages.length == \old(messages.length) - 1 &&
@ (\forall int i; 0 <= i && i < \old(messages.length) && \old(messages[i].getId()) != id;
@ (\exists int j; 0 <= j && j < messages.length; messages[j].equals(\old(messages[i]))));
@ ensures advertise.advertiserProduct.contains(products)
@ ensures (\forall int i; 0 <= i && i < \old(advertise.advertiserProduct.size());
(\exits int j; 0 <= j && j < advertise.advertiserProduct.size();
old\(advertise.advertiserProduct.get(i)) == advertise.advertiserProduct.get(j)));
@ also
@ public exceptional_behavior
@ signals (MessageIdNotFoundException e) !containsMessage(id);
@ signals (ProductNotFoundException e) countOfProducts.get(product) == 0;
*/
public void sendAdvertisement(Product product, Advertiser advertise);
- Customer:消费者,会关注广告并选择和自己偏好匹配的产品来购买
*@ public normal_behaviour
@ requires message instanceof purchaseMessage;
@ requires contains(advertiserId) &&
@ (getPerson(advertiserId) instanceof Advertiser);
@ requires !getPerson(advertiserId).containsMessage(message.getId())
@ assignable getPerson(advertiserId).message[];
@ ensuers getPerson(advertiserId).message.length == \old(getPerson(advertiserId).message.length) &&
@ getPerson(advertiserId).containsMessage(message.getId());
@ also
@ public exceptional_behavior
@ signals (PersonIdNotFoundException e) !contains(advertiserId);
@ signals (WrongMessageTypeException e) !(message instanceof purchaseMessage);
@*/
void purchase(int advertiserId, Message message) throws
PersonIdNotFoundException, WrongMessageTypeException;
五、学习体会
这个单元我体会到了JML规格的严谨性。使用JML可以无二义性地描述自己的需求,并且对程序的实现也较为友好。但编写JML挺麻烦的,需要多加练习。阅读JMl规格时一定要搞清楚()的作用范围。程序的模块化很重要。在对于qlc,sim等命令在开发中需要更低的时间复杂度时,能够模块化封装运算,编写时很方便。