首页 > 其他 > 详细

BUAA_OO第三单元总结

时间:2021-05-29 12:28:23      阅读:11      评论:0      收藏:0      [点我收藏+]

面向对象第三单元总结

一、实现规格所采取的设计策略

? 首先,先看public instance model non_null要创建哪些,对类的组成成员有个了解,但是不立马实现,不随意开ArrayLsit存,因为可能两个合在一起用HashMap更好。例如 Person类中用HashMap存acquaintance和value更好。

? 之后就是从易到难的去实现。例如containsequalssetxxxxgetxxx等十分容易的函数。实现的时候要关注requiresensures来理解相应的返回值是在什么时候。

? 当实现完简单的规格后。就需要去实现那些比较长的规格函数。我采取的策略是先读懂规格在干什么,先整个了解各个函数之间在做什么,方便优化,防止TLE。当了解完之后,就会采取相应的方法去实现,顺带优化之前的一些容易的方法。例如算group的value Sum的时候,就不需要重复的循环,而是在加入人的时候就维持一个变量来存取。

二、基于JML规格来设计测试的方法和策略

? 本单元我对于我写的比较薄弱进行了JML测试,例如采用了junit来测试sim,qci,qbs等。不过我在写的时候十分仔细,并且多次进行了形式验证,所以不会出现抛异常错误这种错误以及函数实现的大问题。

? 但是本单元最大的难点就是防止超时的问题,例如qbs,qgvs,qgam如果照着规格进行翻译,必超时。所以在实现的时候,还需要判断一下自己的算法的时间复杂度是不是O(n^2),如果是,那可能就需要换方法了。让复杂度降下来。

? 所以为了测运行时间,用到python来测cpu运行时间(大佬写的程序)。并且自动生成极端数据来测试时间。根据时间来判断方法是否会被TLE。

? 判断正确性上,还是用到了对拍。和同学之间比对输出结果来找一些bug,例如整数除法这种会舍弃尾数,并不是我们数学上理解上的那种运算。

三、总结分析容器选择和使用的经验

容器我选用了ArrayListHashMapPriorityQueue

在找成员在不在的时候,或是找特定的成员时。HashMap的效率以及使用上会明显优于ArrayList。并且HashMap可以实现覆盖,相同的key对应的value可以修改,所以基本上我的所有数组都是由HashMap去实现的。

不过在移出容器中的数据时。还是那个问题,别采用for的方式去删除,会出错,要采取迭代器的方式。或者是

public int deleteColdEmoji(int limit) {
    emojiIdHeat.entrySet().removeIf(entry -> (entry.getValue() < limit));
    messages.entrySet().removeIf(entry -> ((entry.getValue() instanceof EmojiMessage)
            && !containsEmojiId(((EmojiMessage) entry.getValue()).getEmojiId())));
    return emojiIdHeat.size();
}

这样的lambda表达式。

最后我再总结一下PriorityQueue这个优先队列。我是用这个容器的目的,是为了在找最短路径的时候进行一个堆优化。这个容器在一开始我理解错了用法,我以为在add的时候,会对列表中所有的元素进行排列。谁知道不是并且还不会覆盖,机制是将该插入元素按照大小插进去,并不会排余下的元素。所以在使用的时候,不得不改变一下思路,在每一次遍历的时候都加进队列,当出堆的时候,判断改成员的最短路径是否找到,如果找到了,就弹出下一个。

Person p = waiting.poll();
while (alFind.containsKey(p.getId()))
{
    p = waiting.poll();
}

这个队列的用法还需要写一个compare函数。

static class MyComp implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        return ((MyPerson) o1).getDistance() - ((MyPerson) o2).getDistance(); } }

四、总结性能问题

? 性能上在查联通性上,算value,算ageValue的时候,以及最短路径会出现问题。原因就可能将问题想简单了,认为翻译jml就行了。但是这样发现,复杂度往往是O(n^2)。所以在写的时候,要将整个代码了解清楚,知道这个函数在干什么,以及和另外函数的联系。

? 例如算value的情况,完全可以在add或delete的时候,对value进行操作,再取value的时候完全不需要遍历,直接返回value就可以了,大大提高了效率。

? 再一个在查询连通块数的时候。不能够按照isCircle去遍历,必超时。而是去用并查集,或是直接深度搜索递归,可以有效解决这个问题。

? 在算ageValue的时候,如果按指导书上说的,虽然一个函数里用的是一个for,但是殊不知,这个for里面调用了另一个函数,这个函数也在for,从而就复杂度O(n^2)了。所以这也是一样的解决思路,将复杂度换成O(1)。跟value的解决方法类似,在add,delete的时候操作好。

? 最后就是在查最短路径的时候,如果用弗洛伊德算法,直接就tle了,复杂度是O(n3)。如果用不优化的迪杰斯特拉算法的话,时间复杂度是O(n2)。但是写的时候就会发现,每次都要去遍历找最小值的复杂度很慢,很拖累性能。所以解决方法就是设计个堆,使得堆顶的元素是最小的,直接取就够了,大大增强了效率。

五、梳理作业架构设计

? 这次作业的架构是由规格去提供,自己没有改变很多。总体就是PersonMessage们,GroupNetwork这几个大类,以及抛异常的类。Network中进行将人加入群聊,发各种信息,算认识人的各种操作,大体上应该就是这样。相对来说这次单元的作业并不像前两次那么难,架构上面相对来说不难,极易理解。难点在于有些函数的实现上,考虑时间复杂度上。

BUAA_OO第三单元总结

原文:https://www.cnblogs.com/1754917862Tao/p/14824459.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!