标签:OO HashMap get int BUAA private key new 单元
BUAA_OO 第三单元总结
一、架构设计
本单元的三次作业核心是增量开发一个多人聊天系统,由于是迭代开发,所以在此处主要就本单元第三次作业进行分析。
容器选择
为了降低整体的时间复杂度,且本次作业拥有互不相同的Person
、Group
等对象拥有互不相同的id的特点,所以在用到容器时许多我都是优先用Hashmap
,这样使我每次查找操作都快了很多。例如:
private HashMap<Integer, Person> people = new HashMap<>();
private HashMap<Integer, Group> groups = new HashMap<>();
private HashMap<Integer, Message> messages = new HashMap<>();
private HashMap<Integer, Integer> emo = new HashMap<>();
private HashMap<Person, Integer> acquaintance = new HashMap<>();
private HashMap<Integer, Integer> value = new HashMap<>();
有一次特殊的地方就是MyPerson
类中我存储message用了 LinkedList
容器,这是因为要求将新来的消息存到容器的头部,如果选择其它容器,一般都会插到尾部或位置不定,所以我选用了 LinkedList
容器。
private LinkedList<Message> messages = new LinkedList<>();
在sendIndirectMessage
函数中,为了更好应用dijkstra
算法,我又用了优先队列 PriorityQueue
来存储距离,用 HashSet
来存储已经访问过的点。
private PriorityQueue<Distance> pq = new PriorityQueue<>();
private HashSet<Integer> visit = new HashSet<>();
时间复杂度较高方法的总结
在本单元作业中,大部分方法的复杂度都不高,简单实现JML规格即可,再加上选择了效率高的容器,所以可以有很好的性能。但如果仅仅如此,还有以下方法的时间复杂度很高,需要用算法进行优化。它们是:
MyNetwork类中的:
-
boolean isCircle(int id1, int id2)
-
int queryBlockSum()
-
int queryLeastConnectionid)
:
-
int sendIndirectMessage(int id)
MyNetwork类中的:
-
int getAgeVar()
-
int getValueSum()
对应优化策略
对于boolean isCircle(int id1, int id2)
我采用了并查集算法。用了private HashMap<Integer, Integer> parent = new HashMap<>();
和private HashMap<Integer, Integer> rank = new HashMap<>();
两个容器。在每进入一个人时,将它加入parent中,每添加关系时,将两个人进行merge,最后通过find函数判定是否二者处于同一连通分支(即是否isCircle)。函数具体实现如下:
private int find(int p) {
int tmp = p;
while (tmp != parent.get(tmp)) {
tmp = parent.get(tmp);
}
return tmp;
}
public void merge(int p, int q) {
int proot = find(p);
int qroot = find(q);
if (proot == qroot) {
return;
}
blockSum--;
if (rank.get(proot) < rank.get(qroot)) {
parent.put(proot, qroot);
} else if (rank.get(proot) > rank.get(qroot)) {
parent.put(qroot, proot);
} else {
parent.put(proot, qroot);
int tmp = rank.get(qroot);
rank.put(qroot, tmp + 1);
}
}
细心的同学可能已经注意到在上面的merge
函数中我同时维护了blocksum
这一变量,这就是为了int queryBlockSum()
函数,该函数就是查询连通分支的个数,只需在在每进入一个人时将其加一,在merge
时将其减一,即可使其变为O(1)
复杂度。
对于int queryLeastConnectionid)
:我采用了利用kruskal算法实现最小生成树的查询。具体实现如下:
public /*@ pure @*/ int queryLeastConnection(int id) throws PersonIdNotFoundException {
if (!contains(id)) {
throw new MyPersonIdNotFoundException(id);
} else {
int sum = 0;
ArrayList<Edge> tmpEdges = new ArrayList<>();
HashSet<Integer> tmpSet = new HashSet<>();
for (int i = 0; i < edges.size(); i++) {
if (find(edges.get(i).getId1()) == find(id)) {
tmpEdges.add(edges.get(i));
tmpSet.add(edges.get(i).getId1());
tmpSet.add(edges.get(i).getId2());
}
}
for (Integer key : tmpSet) {
parent2.put(key, key);
rank2.put(key, 1);
}
Collections.sort(tmpEdges);
int j = 0;
for (int i = 0; i < tmpEdges.size(); i++) {
if (find2(tmpEdges.get(i).getId1()) != find2(tmpEdges.get(i).getId2())) {
merge2(tmpEdges.get(i).getId1(), tmpEdges.get(i).getId2());
sum += tmpEdges.get(i).getValue();
j++;
}
if (j == (tmpSet.size() - 1)) {
break;
}
}
return sum;
}
}
对于int sendIndirectMessage(int id)
函数,我采用了迪杰斯特拉算法+堆优化,通过java提供的PriorityQueue
实现堆优化。具体实现如下:
private int dijkstra(Person person1, Person person2) {
pq.clear();
minDis.clear();
visit.clear();
minDis.put(person1.getId(), 0);
pq.add(new Distance(0, person1));
while (!pq.isEmpty()) {
Distance dis = pq.poll();
Person person = dis.getPerson();
int distance = dis.getDistance();
if (person.equals(person2)) {
return distance;
}
if (visit.contains(person.getId())) {
continue;
}
visit.add(person.getId());
HashMap<Person, Integer> acquaintance = ((MyPerson) person).getAcquaintance();
for (Person key : acquaintance.keySet()) {
if (minDis.get(key.getId()) == null) {
minDis.put(key.getId(), INF);
}
int oriDistance = minDis.get(key.getId());
if (oriDistance > distance + person.queryValue(key)) {
int newDistance = distance + person.queryValue(key);
minDis.put(key.getId(), newDistance);
pq.add(new Distance(newDistance, key));
}
}
}
return -1;
}
对于int getAgeVar()
和int getValueSum()
其优化的方法就是维护变量。
前者我维护了 ageSum
和ageVar
两个变量,最后运用 (ageVar - 2 * getAgeMean() * ageSum + people.size()*getAgeMean() * getAgeMean()) / people.size()
式子进行计算。
后者我维护了valueSum
这一变量。
异常处理
这里我并没有实现一个计数类,因为我觉得使用一个静态变量sum
进行记录即可。
二、测试数据准备
防止公测部分发生bug,我采用了对自己的代码运用随机生成的测试数据进行测试,同时与小伙伴们进行对拍的方式。
对于互测部分的hack,我会对同房伙伴的代码运用随机生成的测试数据进行测试,看是否有正确性问题。此外我采用构造极端数据的方式,多次执行时间复杂度高的指令来卡TLE。
三、BUG分析
本单元的三次作业由于运用了上文所述的策略后在公测和互测中均没有出现bug,并且运行时间都远远小于公测测试点要求的最大运行时间。
标签:OO,HashMap,get,int,BUAA,private,key,new,单元 来源: https://www.cnblogs.com/herbert152301/p/16347608.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。