OO 第三单元博客作业
架构设计
异常
private static int count = 0;
private static HashMap<Integer, Integer> id2Count = new HashMap<>();
private final String msg;
-
count
统计总发生次数 -
id2Count
统计相应 id 发生该异常的次数 -
msg
存需要print
的信息
3-1
/*@ public instance model non_null Person[] people;
@ public instance model non_null Group[] groups;
@*/
-
这种写法只是代表这一对象中需要存储那些实例,并不代表实现时完全采用数组存储
-
第一次作业对JML理解还不到位,所以均采用了
ArrayList
。其实为了方便查询方法的实现时可以采用HashMap
MyPerson
// Attribute
private final int id;
private final String name;
private final int age;
private final ArrayList<Person> acquaintance;
private final ArrayList<Integer> value;
private int fa;
// Operation
public int getFa();
public int SetFa();
...
-
MyPerson
增加属性Fa
,用来存Person
的父节点 -
getFa
和SetFa
用于维护Fa
MyGroup
// Attribute
private int id;
private ArrayList<Person> people;
private int valueSum;
// Operation
public void addPerson(Person person);
public int getValueSum();
public void delPerson(Person person);
...
-
考虑到
qgvs
单纯按 JML 来实现,有 O(n^2) 的时间复杂度-
增加
valueSum
,在addPerson
和delPerson
时,实现 O(n) 维护;在getValueSum
时实现 O(1) 查找
-
MyNetWork
// Attribute
private final ArrayList<Person> people;
private final ArrayList<Group> groups;
private int blockSum;
// Operation
private int find(int id);
public void addRelation(int id1, int id2, int value);
public boolean isCircle(int id1, int id2);
public int queryBlockSum();
...
-
people 与 groups 采用
ArrayList
, -
ar
,qbs
和isCircle
最初并未采用并查集实现,其中qbs
直接使用 BFS
3-2
Message 相关类省略
MyPerson
// Attribute
private final HashMap<Person, Integer> acquaintance;
private int money;
private int socialValue;
private final ArrayList<Message> messages;
...
// Operation
public void getEdges(ArrayList<Edge> edges);
public List<Message> getReceivedMessages();
...
-
getEdges
用于为qlc
提供边集合; -
getReceiveMessages
的简便写法:messages.subList(0, Math.min(messages.size(), 4))
MyNetWork
// Attribute
private final HashMap<Integer, Person> people;
private final HashMap<Integer, Group> groups;
private final HashMap<Integer, Message> messages;
private final ArrayList<Edge> edges;
private int blockSum;
// Operation
public int queryLeastConnection(int id);
...
-
qlc
本质为找到 id 所在连通分量的最小生成树,返回边权值总和;采用 Kruskal 算法不会超时。 -
qlc
实现:-
找到与 id 位于同一个连通分量的所有
Person
edges.clear();
int fa = find(id);
ArrayList<Integer> set = new ArrayList<>();
for (Integer pid : people.keySet()) {
if (find(pid) == fa) {
set.add(pid);
((MyPerson) getPerson(pid)).getEdges(edges);
}
}-
重置这些 Person 的 Fa,并把边排序:此处 Kruskal 采用并查集实现更容易
for (Integer pid : set) {
((MyPerson) getPerson(pid)).setFa(pid);
}
edges.sort(Comparator.comparingInt(Edge::getValue));-
遍历 edges 集合,当满足
num_Vertex == num_Edge + 1
时结束遍历
int numE = 0;
int numV = set.size();
int res = 0;
for (Edge edge : edges) {
if (numV - 1 == numE) {
break;
}
int id1 = edge.getPerson1().getId();
int id2 = edge.getPerson2().getId();
int fa1 = find(id1);
int fa2 = find(id2);
if (fa1 != fa2) {
((MyPerson) getPerson(fa1)).setFa(fa2);
res += edge.getValue();
numE++;
}
}
return res; -
3-3
Message 相关类省略
MyNetWork
// Attribute
private final HashMap<Integer, Integer> emojiId2Heat;
// Operation
public int sendIndirectMessage(int id);
...
-
sim
本质是求 id 对应的 Message 中,Person1 到 Person2 的最短路 -
sim
实现:Person person1 = getMessage(id).getPerson1();
Person person2 = getMessage(id).getPerson2();
if (find(person1.getId()) != find(person2.getId())) {
return -1;
}
HashMap<Integer, Integer> dis = new HashMap<>(); // id->dis
PriorityQueue<Pair<Integer, Integer>> pq = // dis->id, 按距离权值排序
new PriorityQueue<>(Comparator.comparingInt(Pair::getKey));
dis.put(person1.getId(), 0); // 把原点的dis置0, 刚进循环时从原点开始
pq.add(new Pair<>(0, person1.getId())); // 加入优先队列
while (!pq.isEmpty()) {
Pair<Integer, Integer> u = pq.poll(); // 队头一定是已经找到最小距离的点
HashMap<Person, Integer> acquaintance = // 遍历所有邻接点
((MyPerson) getPerson(u.getValue())).getAcquaintance();
for (Map.Entry<Person, Integer> p : acquaintance.entrySet()) {
if (!dis.containsKey(p.getKey().getId()) || // 距离小时修改
u.getKey() + p.getValue() < dis.get(p.getKey().getId())) {
dis.put(p.getKey().getId(), u.getKey() + p.getValue());
pq.add(new Pair<>(u.getKey() + p.getValue(), p.getKey().getId()));
}
}
if (u.getValue() == person2.getId()) { // 找到直接返回
break;
}
}
sendPpmRemain(person1, person2, id); // remain
return dis.get(person2.