OO第三单元总结
OO第三单元总结
(1)实现规格要求所采取的设计策略
MyMessage,MyEmojiMessage,MyNoticeMessage,MyRedEnvelopeMessage按照指导书要求实现构造方法,随后实现相应的get(),set()方法和equal()方法即可。
Main函数按照指导书给出的实现即可。
MyPerson除了需要实现的属性,使用了四个容器来实现相应的操作
private LinkedList<Message> messages;
//记录接收到的message,使用LinkedList方便实现规格要求的在所有Message的头部插入
private HashMap<Integer, MyPerson> acquaintanceMap;
//记录这个Person和那些Person相连,key表示连接到的Person的id,value表示相应的Person
private HashMap<Integer, Integer> valueMap;
//记录和这个Person相连的Person的边的value,key表示连接到的Person的id,value表示相应边的value值
//经过分析发现,其实可以把这两个HashMap合成一个,key值代表连接的Person的id,value代表这条边的value值
private HashMap<Integer, Group> inGroup;
//记录这个Person在那些Group中,key表示Group的id,value代表相应的Group,用于优化MyGroup的getValueSum()方法
一些方法的实现策略:
addRelation()除了要在acquaintanceMap和valueMap中增加相应的key-value值,还需要把Person所在的Group的valueSum增加这条边的value值- 除规格要求的方法外,还实现了
- addAtHead()增加收到的Message
- addInGroup()增加Person所在的Group,Group中addPerson()时调用
- removeInGroup()减少Person所在的Group,Group中delPerson()时调用
MyGroup除了需要实现的属性,使用了一个容器来实现相应的操作
private HashMap<Integer, Person> people;
//记录Group中包含那些人,key表示Person的id,value表示相应的Person
一些方法的实现策略:
- 为了实现O(1)的getValueSum()和getAgeMean(),每次加入/删除Person的时候动态更新ageSum,而valueSum除了需要在加入/删除Person的时候更新,还需要在增加一条边的时候更新,因此,在Person中定义了inGroup(),方便动态更新。
MyNetwork使用如下方法来实现规格
private HashMap<Integer, Person> personMap;
//记录Network中包含那些人,key表示Person的id,value表示相应的Person
private HashMap<Integer, Integer> root;
//并查集的根数组,因为id范围并非从0或1开始的连续整数,可以选择离散化或者使用HashMap直接代替数组,在冲突不多的条件下,可以认为HashMap的查询是O(1)的,和数组并没有很大的时间效率上的差距。
private int blockNum;
//记录连通块的个数
private HashMap<Integer, Group> groupById;
//记录Network中的Group,key表示Group的id,value表示相应的Group
private HashMap<Integer, Message> messageById;
//记录所有Message,Key表示Message的id,value表示相应的Message
private HashMap<Integer, Integer> emojiById;
//EmojiMessage按emojiId分类,value值选择hashmap方便删除
一些方法的实现策略:
isCircle(),queryBlockSum()为较快的实现,使用并查集,可以加边的同时,维护一个blockSum记录连通块的个数sendIndirectMessage()使用堆优化的Dijkstra算法来计算最短路,时间复杂度为O((m+n)logn)。
任一级中的contain方法均可以通过HashMap的contains。
(2)结合课程内容,整理基于JML规格来设计测试的方法和策略
- 首先在基本了解JML语法的基础上,通读JML规格,了解规格希望实现的内容,主要是相应的方法和需要支持的查询方式。
- 考虑数据范围和时间,选择可以在给定时间内完成查询的实现方法,实际上整体上只要选用了合适的容器,只有几个方法需要去考虑如何优化,其余方法直接调用容器的相应方法即可实现。
- 理解相应类的包含关系,实现规格定义的方法。
(3)总结分析容器选择和使用的经验
- 除了存储Person接收的Message之外全部采用的HashMap。
- Person中记录此Person接收的Message采用LinkedList因为要支持在头部插入,采用链表可以很方便的实现。
- 其他情况均选择HashMap因为HashMap可以以很快的效率实现增,删,查,改,这也是本次OO作业主要需要实现的功能,通过建立id到自身的HashMap可以很快的查找某一类的实例,从而实现规格所要求的方法。
(4)针对本单元容易出现的性能问题,总结分析原因
isCircle(),queryBlockSum()不能每次都按照相应的定义去查,使用并查集,来判断两个节点上是否存在联通路,然后在添加边的时候,动态维护一个int blockNum,保存连通块的个数即可- Group中的
getValueSum(),getAgeMean()为了提高最坏情况下的时间效率,采用了O(n)的添加/删除和O(1)的查询,而不是O(1)的插入/删除和O($n^2$)的查询,在查询不太多的情况下(比如添加n个人查询1次),二者的摊还时间基本一致,但是当查询的比重变多时,前者有明显的时间效率的优势 sendIndirectMessage()中需要计算最短路,使用堆优化的Dijkstra算法,时间复杂度为O((m+n)logn),堆优化时使用java自带的优先队列存储自定义的Edge类的对象,表示当前到某个点的最短距离。
(5)梳理自己的作业架构设计,特别是图模型构建与维护策略
Network中包含Person,Group,每个Group中又包含相应的Person,可以认为把一个无向图分成了很多组,每一组就是一个Group
第三次作业的UML类图如下(选择MyMessage,MyPerson,MyGroup,MyNetwork画出相应类图)

浙公网安备 33010602011771号