• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Healwh
博客园    首页    新随笔    联系   管理    订阅  订阅
BUAA_OO_UNIT3

BUAA_OO_UNIT3

第一次作业

设计策略

按照jml的描述完成各个接口,实现接口中的方法

测试方法

手动构造样例之后和同学的结果比较,很难找到自己的问题也无法判断cpu时间,果然在强测和互测中被打傻了

容器选择

由于每个person的id是唯一的,且需要从id查询到person,很自然的想法就是使用HashMap来存储,id作为key,person作为value

性能问题

第一次作业的jml描述和接口都十分简单,导致我没有多加思考,直接按照jml的描述把所有的方法完成,导致强测和互测时超时十分严重,强测挂掉了6个点。最后在bug修复时改用并查集的做法才避免了ctle。

图模型构建与维护策略

第一次作业时我并没有考虑到图,只是简单地把各个方法的jml描述加以实现,在第二次作业时才考虑图的算法

第二次作业

设计策略

第二次策略加入了Group类和Message类,Message类中只需要按照jml规格描述一步步实现就好。

Group类中如果只是简单的按照jml描述的写出方差的计算结果,时间复杂度为O(n2),很容易出现ctle,因此我在Group中维护了ageSum和ageSqrSum三个变量来求方差。而求方差时容易出错的点为一下写法

 (ageSquaredSum - 2 * mean * ageSum) / people.size() + mean * mean;

会出现由于向上取整导致的负数的错误

要非常小心的点是除了addPerson和delPerson是会导致valueSum的改变,已经在一个group中的两个person,在network中addRelation时,也会改变valueSum,因此我增加了一个setValueSum的方法。

测试方法

这次我吸取了第一次作业中样例过少和无法判断cpu时间的教训,使用python中的time库来判断cpu时间

容器选择

依然采用HashMap来存储Group和Message,key都是id,value为group和message

性能问题

由于吸取了第一次作业大量ctle的教训,第二次作业我在处理person有关请求时采用了并查集,维护连通分量数,保证qbs请求的时间复杂度为O(1),并且在Group的求方差的方法中也使用了时间复杂度为O(1)的查询,使这次测试并没有出现ctle。

但由于我的粗心,在sendMessage方法中,错将PersonId的异常抛出写成了MessageId,导致强测挂了一个点,实在很不应该。

图模型构建与维护策略

由于第一次作业挂的点太多,从第一次作业的bug修复开始,我就开始注重图模型的构建,并且我渐渐明白了老师课上所说的,jml描述并不规定方法的具体实现方式,我在多次阅读jml规格之后,理解了jml所描述的内容和图的知识所对应起来,再进行对方法的实现,可以让代码的编写更加简单。

维护策略是维护一个并查集,在Network中,实现HashMap<id,father_id>存储每个用户和其祖先的id。在addPerson方法中,新增id对应的键值对,将father_id设为自己。在addRelation方法中,合并两个人的father_id。另实现find方法,路径压缩+返回祖先。在isCircle方法中,对两个id分别find出祖先,以判断二人是否连通。

第三次作业

设计策略

这一次作业在第二次作业的基础上增加了EmojiMessage RedEnvelopeMessage和NoticeMessage这三个类,这三个类继承字Message类,没什么好说的。

在Network中增加了若干方法,其中值得注意的是sendIndirectMessage 和 deletColdEmoji。

sendIndirectMessage方法中需要注意的是求最短路径。我的方法是采用迪杰斯特拉算法的堆优化方法,如果不堆优化可能会ctle。具体实现方法为,新建MyPair类,包含属性id和dis(表示到起点的距离),在Network中实现比较器。但之后我认为更优雅的做法是在MyPair内部实现Comparable接口,重写compareTo方法。

deleteColdEmoji要注意的就是除了要将EmojiMessage从Emoji容器中删除,还要将其从messages中删除,这一点也让我最开始提交时产生了一次错误。

测试方法

本次作业我使用了同学的评测机,大致思路和第二次作业我的测试方法类似,只是大佬的评测机对可能出错的点、卡t的点都有特殊的构造,这种构造样例的能力是我所欠缺的。

容器选择

依然使用HashMap来存储新增的id和对应的对象

性能问题

这次作业在弱测中测强测互测中均没有bug,同一个room中也没有同学hack出了其他同学代码的问题。

感想

本单元的代码和前两个单元相比难度下降了很多,但对我个人而言,前两次作业的强测结果和前两个单元相比却很不理想,我认为是我自己对规格的理解不透彻导致的。

在根据JML规格书写代码时,读懂jml规格描述并且按照其要求一步一步将代码写对并运行正确并不难,但很多时候我们要理解其规格描述背后的深意,比如第一次作业的isCircle、queryBlockSum方法,第二次作业的方差计算,第三次作业的最短路径。只要分析出了这些背后的东西,那么分别对其真正要表示的内容进行维护、优化,就显得不那么困难了。

和前两个单元相比,这个单元的代码书写体验变得很好,在这个单元的学习之后,除了了解了jml规格描述,我也在代码官方包的架构中学习到了很多如何组织我的代码层次的知识,相信如果现在让我重新写第一第二单元的作业,我的代码一定会比之前的更加清晰易懂。

posted on 2021-05-31 09:19  Healwh  阅读(59)  评论(1)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3