OO第三单元总结
第三单元总结
一、 本单元自测过程中如何利用JML规格来准备测试数据
本单元自测过程一般分为两个方面:
(1)定点爆破:
针对JML规格当中的每一个条件的触发点进行有针对性的爆破,看一下每个条件下能否按要求抛出错误或者完成指定操作内容.
(2)重复爆破
重复爆破可针对某一种情况重复造不一样的边际数据来测试该情况下对于本情况下的各种数据是否能够具有反馈的一致性.
也可针对某一个特定的方法规格进行定点重复爆破,记录时间来判断哪一个方法类复杂度过高需要优化
二、梳理本单元的架构设计,分析自己的图模型构建和维护策略
代码架构设计均按照JML规格设计,添加个一个Edge类用来存边方便查询.
本单元中person为图的点,relation为图的边,group可以看作点集。为了方便后续的查询,采用了维护了每个点集所属的极大连通子图。在加入点时为其创建并查集,最小生成树算法来判断block(块)的个数,在加入边时若两个并查集不相同将其合并。
最小生成树使用kruscal算法
public int kruskal(int id) throws PersonIdNotFoundException {
ArrayList<Integer> nodes = new ArrayList<>();
ArrayList<Edge> edges = new ArrayList<>();
int[] ends = new int[2505];
int result = 0;
for (Person person : people) {
if (isCircle(id, person.getId())) {
nodes.add(person.getId());
edges.add(new Edge(person.getId(), person.getId(), 0));
}
}
for (Edge value : edgeArrayList) {
if (nodes.contains(value.getStart()) && nodes.contains(value.getEnd())) {
if (getPosition(nodes, value.getStart()) < getPosition(nodes, value.getEnd())) {
edges.add(value);
} else {
edges.add(new Edge(value.getEnd(), value.getStart(), value.getWeight()));
}
}
}
edges.sort(Edge::compareTo);
for (Edge edge : edges) {
int p1 = getPosition(nodes, edge.getStart());
int p2 = getPosition(nodes, edge.getEnd());
int n = getEnd(ends, p1);
int m = getEnd(ends, p2);
if (n != m) {
ends[n] = m;
result += edge.getWeight();
}
}
return result;
}
最短路径使用dijkstra算法
public int dijkstra(int id1, int id2) {
HashMap<Integer, Integer> pending;
pending = new HashMap<>();
HashMap<Integer, Integer> solved;
solved = new HashMap<>();
ArrayList<Edge> edges = new ArrayList<>();
for (Person person : people) {
if (find(id1) == find(person.getId())) {
pending.put(person.getId(), INF);
}
}
for (Edge edge : edgeArrayList) {
if (pending.containsKey(edge.getStart()) && pending.containsKey(edge.getEnd())) {
edges.add(edge);
}
}
pending.remove(id1);
solved.put(id1, 0);
int lastSolved = id1;
int minValue = 0;
while (lastSolved != id2) {
for (int i = 0; i < edges.size(); i++) {
Edge edge = edges.get(i);
if (solved.containsKey(edge.getStart()) && solved.containsKey(edge.getEnd())) {
edges.remove(edge);
i--;
} else if (pending.containsKey(edge.getStart())
&& solved.containsKey(edge.getEnd())) {
pending.put(edge.getStart(), min(pending.get(edge.getStart()),
edge.getWeight() + solved.get(edge.getEnd())));
} else if (pending.containsKey(edge.getEnd())
&& solved.containsKey(edge.getStart())) {
pending.put(edge.getEnd(), min(pending.get(edge.getEnd()),
edge.getWeight() + solved.get(edge.getStart())));
}
}
minValue = INF;
for (Integer key : pending.keySet()) {
if (minValue > min(minValue, pending.get(key))) {
minValue = min(minValue, pending.get(key));
lastSolved = key;
}
}
solved.put(lastSolved, minValue);
pending.remove(lastSolved);
}
return minValue;
}
三.按照作业分析代码实现出现的性能问题和修复情况
每次作业出现的性能问题都是某一方法复杂度大于了O(n^2),需要对算法进行一定程度上的优化,如并查集的算法终止条件,或者对于一些重复性访问操作能否用空间换时间,提前将用户需要求的变量存储起来,访问的时候直接输出就行.
四.请针对下页ppt内容对Network进行扩展,并给出相应的JML规格
假设出现了几种不同的Person
-
Advertiser:持续向外发送产品广告
-
Producer:产品生产商,通过Advertiser来销售产品
-
Customer:消费者,会关注广告并选择和自己偏好匹配的产品来购买 -- 所谓购买,就是直接通过Advertiser给相应Producer发一个购买消息
-
Person:吃瓜群众,不发广告,不买东西,不卖东西
如此Network可以支持市场营销,并能查询某种商品的销售额和销售路径等 请讨论如何对Network扩展,给出相关接口方法,并选择3个核心业务功能的接口方法撰写JML规格(借鉴所总结的JML规格模式)
Porduder、Advertiser、Customer均继承Person类,同时给Network增加products属性。
1.购买产品
/*@ public normal_behavior
@ requires (\exists int i; 0 <= i && i < people.length; people[i].getId() ==
@ customerId && people[i] instanceof Customer) && (\exists int i; 0 <= i &&
@ i<= messages.length;messages[i].getId() == advertiseId && messages[i]
@ instance of advertise)
@ assignable poeple[*],money;
@ ensures messages.length == \old(messages.length) + 1
@ ensures getPerson(customerId).money == \old(getPerson(customerId).money) -
@ getMessage(advertiseId).getPrice()
@ ensures getPerson(getMessage(advertiseId).getProducer()).money ==
@ \old(getPerson(customerId).money) + getMessage(advertiseId).getPrice()
@ ensures (\forall int i; 0 <= i && i < people.length;
@ (people[i].id != customerId && people[i].id !=
@ getMessage(advertiseId).getProducer() ==> people[i].money == \old(people[i].money)
@ also
@ public exceptional_behavior
@ signals (PersonIdNotFoundException e)
@ (\forall i; 0 <= i && i < people.size; !people[i].equals(producer))
@ signals (MessageIdNotFoundException e) !containsMessage(id);
@*/
public void buy(int customerId,int advertiseId) throw PersonIdNotFoundException, MessageIdNotFoundException;
2.添加推广产品
/*@ public normal_behavior
@ requires (\exists int i; 0 <= i && i < people.length;
@ people[i].getId() == id && people[i] instanceof Producer);
@ assignable products;
@ ensures products.length == \old(products.length) + 1;
@ ensures (\exists int i; 0 <= i && i < products.length; products[i] ==
@ product);
@ ensures (\forall int i; 0 <= i && i < \old(products.length);
@ (\exists int j; 0 <= j && j < products.length; products[j] ==
@ (\old(products[i]))));
@ also
@ public exceptional_behavior
@ signals (PersonIdNotFoundException e)
@ (\forall i; 0 <= i && i < people.size; !people[i].equals(producer))
@*/
public void addProduct(Product product, int id) throws PersonIdNotFoundException;
3.推送广告
/*@ public normal_behavior
@ requires (\exists int i; 0 <= i && i < people.length; people[i].getId() ==
@ id && people[i] instanceof Advertiser) && (\exists int i; 0 <= i && i<=
@ products.length;products[i].getId() == adcertise.getProductId())
@ assignable messages;
@ ensures messages.length == \old(messages.length) + 1
@ ensures (\exists int i; 0 <= i && i < messages.length; messages[i] ==
@ advertise);
@ ensures (\forall int i; 0 <= i && i < \old(messages.length);
@ (\exists int j; 0 <= j && j < messages.length; messages[j] ==
@ (\old(messages[i]))));
@ also
@ public exceptional_behavior
@ signals (PersonIdNotFoundException e)
@ (\forall i; 0 <= i && i < people.size; !people[i].equals(producer))
@*/
public void advertise(int id,Message advertise) throw PersonIdNotFoundException;