一、总结分析自己实现规格要求所采取的设计策略
首先分析要抛出哪些异常情况,把异常情况都抛完了再处理正常情况。
先通过JML读懂这个函数要实现什么功能,然后考虑有没有时间复杂度更优的实现方法。
二、基于JML规格来设计测试的方法和策略
JUnit:JUnit是一个开放源代码的Java测试框架,用于编写和运行可重复的测试。
OpenJML:OpenJML能够检查代码是否符合JML规范。最基本的功能就是对JML注释的完整性进行检查。可以对规格内容进行检查也可以执行运行时检查。
JMLUnitNG:JMLUnitNG是用于带有JML注释的Java代码的自动化单元测试生成工具。
和同学对拍。
三、容器选择和使用的经验
键值对用HashMap存储,单次操作复杂度为常数。
集合用HashSet存储。
有固定顺序的内容用ArrayList存储。
优先队列PriorityQueue
\\Network
private Map<Integer, Person> people;
private Map<Integer, Group> groups;
private Map<Integer, Message> messages;
private Map<Integer, Integer> emojiIdList;
\\Person
private Map<Integer, Edge> acquintance;
private List<Message> messages = new ArrayList<>();
\\Group
private Map<Integer, Person> people;
\\Dijkstra
Queue<HeapNode> q = new PriorityQueue<>();
Map<Integer, Integer> d = new HashMap<>();
Set<Integer> vis = new HashSet<>();
四、性能问题的总结与分析
分析几个重要的操作,自己能想到的比较好的复杂度做法,但是有些并没有去实现。
query_name_rank
可以用平衡树维护所有人的名字,插入O(logn),查询O(logn);
query_circle
路径压缩、按秩合并并查集维护,加边和查询“几乎”常数复杂度。
如果不按秩合并,则数据再大一点点就有爆栈的危险。
query_block_sum
若并查集合并操作,则连通块个数-1,O(1)
query_group_value_sum
atg和dfg时计算,枚举与这个点相连的边,判断另一点是否在Group内。更新O(n),查询O(1)
或者每次查询时枚举每个点,再枚举出边,单次O(n+m)
听@cjy说了一个n*sqrt(n)的做法,但是地方太小写不下了。
query_group_age_mean
关键在求Age的和,atg和dfg时O(1)维护,O(1)查询答案
query_group_age_var
求方差,关键在求\sum (x-t)^2 =(\sum x^2)-2t (\sum x)+ n*t^2
\sum x^2 和\sum x维护同qgam
n为人数,t为平均值。
atg和dfg时O(1)维护,O(1)查询答案
delete_cold_emoji
采用支持删除的小根堆(可以用双堆实现),每次检查堆顶是否可以删除,直到堆顶不能删,能删就查找这个表情对应的Message并删掉Message。复杂度均摊(包括添加表情消息的操作)O(logn)。更新热度要先从堆里删除原热度再添加新热度。
send_indirect_message
采用堆优化Dijkstra算法
每次查询时跑一遍最短路,复杂度O(E log E),E边数
优化,如果从优先队列里取出的点是终点,直接return
理论上强测可以卡掉最短路为O(E log E)复杂度的做法,但是助教们并没有卡,给助教点赞