ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

OO第三单元回顾总结

2022-06-05 20:33:09  阅读:185  来源: 互联网

标签:OO 结点 Group 测试数据 Person 回顾总结 query 单元


目录

前言

本单元围绕JML进行规格化设计,契约式编程的思想基本上贯穿了整个单元。

本单元最大的新体验在于:作为大工程中某一部分代码的实现者,履行应尽的责任,而非像前几个单元一样自行设计完整架构并完成所有代码。更直观的感受在于:由于课程组提供了细化到每一个类和类方法的JML描述,完成作业更像是做一道道小题,颇有一种“闯关”的快感,写起代码来体验极佳!

尽管如此,本单元依然存在一些难点,也存在许多值得探讨的课题,接下来将详细描述。

一、架构设计

本单元主要需要设计Network中的GruopPerson实例的生成、关系建立和查询等方法。其中涉及一些图论知识。

1. 第一次作业

第一次作业的难点在于完成query_circlequery_block_sum两种查询。在实现中,本人使用了并查集算法。

具体而言:结点的连通关系是一种等价关系,具有自反性、对称性和传递性,图中的所有结点可以被分成多个连通分量(参考离散数学知识)。而本单元Person实例间的连通关系是同样的道理,因此可以根据是否连通,将Person划入到多个集合中,互相连通的Person在同一个集合。

在代码实现上,集合的概念通过并查集算法实现,位于同一个集合的Person实例形成一个树状结构,则在查询时,可:

  • 通过判断两个Person所在树状结构的根结点是否相同,判断两个Person是否连通,完成query_circle查询
  • 通过查看有多少个不同的根结点,完成query_block_sum查询
2. 第二次作业

第二次作业的难点在于完成query_least_connection查询,需要设计最小生成树的算法。在实现中,本人使用了Kruskal算法

具体而言:Kruskal算法不断从未选中的边集中选择权重最小的边,尝试将此边加入已选中的边集,并判断引入此边是否会导致的出现。实现的难点就在于判断是否出现了环。在本人的具体实现中,此处也使用了并查集算法,当两个结点依靠已选中的边可连通时,两个结点位于同一个集合。由此,只有当前边连接的两个结点不在同一个集合时,此边才能成功加入。以下图为例:

假如当前结点连接如左图所示,且Kruskal将继续尝试将Edge1和Edge2加入边集:在判断Edge1时:由于结点2和3已经位于同一个集合,因此无法继续加入;而在判断Edge2时:结点5和7位于两个不同的集合,因此可加入此边。

3. 第三次作业

第三次作业的难点在于完成send_indirect_message查询,需要完成最短路径算法。在实现中,本人使用了堆优化的Dijkstra算法

具体而言:Dijkstra算法从当前未到达的结点集合中,选取最近的结点标记为到达,并用此节点更新其他未到达结点的距离。由于需要不断更新结点的当前距离,并涉及选取最近的结点,因此类似于优先队列问题,可以使用小顶堆进行优化。在本人的具体实现中,使用了Java自带的PriorityQueue容器完成。

二、测试数据准备

本单元需要利用JML规格来准备测试数据。总结而言,满足各个类方法前置条件的测试数据均应该覆盖。而本单元真正具有前置条件的类方法非常少,大部分都通过抛出异常解决,因此,测试数据就几乎涵盖了所有可能的情况。

具体来说,本人在构造测试数据时,主要分别构造正常数据和异常数据,并分别对每个异常都构造数据。以addToGruop方法为例:

addToGroup方法设计到三种异常。因此,在构造测试数据时,需要包含:

  1. 正常的测试数据:存在idid1Person,存在idid2Group,且Person目前不在Group
  2. 涉及GroupIdNotFoundException的测试数据:不存在idid2Group
  3. 涉及PersonIdNotFoundException的测试数据:不存在idid1Person
  4. 涉及EqualPersonIdException的测试数据:idid1Person已经位于idid2Group

三、性能分析

本单元严格限制了代码运行时间,以下总结了可能出现性能问题的指令,与本人的解决方案。

1. query_circle与query_block_sum

除了上文中提到的,这两条指令使用并查集完成外。在实现过程中,还需要进行路径压缩。具体而言,路径压缩通过重构并查集的树状结构,减少查询根结点时间。以下图为例:

在查询到结点3的根结点为结点1之后,使结点3直接指向结点1,由此可以减少下次查找结点3根结点时花费的时间。

2. query_group_value_sum

如果在每次收到qgvs指令后,都通过二重循环,遍历Group中两两结点的关系,则时间复杂度为O(n^2),无法通过本单元测试。解决方案是,在Group中维护一个变量valueSum保存此查询的答案。valueSum需要在遇到以下指令时检查是否需要更新:

  1. add_relation:需要检查两个Person是否都位于同一个Group,如果是,则需要更新valueSum
  2. add_to_group:需要检查加入的Person与目前位于Group中的每一个Person是否有关系,如果是,则需要更新valueSum
  3. del_from_group:需要检查删除的Person与目前位于Group中的其他每一个Person是否有关系,如果是,则需要更新ValueSum
3. query_least_connection

如上文所述,利用依赖并查集的Kruskal算法,可以满足时间限制。

4. send_indirect_message

如上文所述,利用堆优化的Dijkstra算法,可以满足时间限制。

四、Network拓展

本人思路如下:构建AdvertiserProducerCustomer三个接口,这三个接口均继承Person接口。并构建Product类,封装产品信息。

Advertiser接口见下。Advertise维护productInfo数组,通过addAdvertise()方法接受来自Producer的产品信息,通过getAdvertise()方法提供产品信息。

Producer接口见下。Producer拥有一个Product实例,封装自身产品信息,同时Producer拥有一个Message变量,存放买家信息。Producer通过useAdvertise()方法向Advertiser提供自身产品信息,通过receiveBuyInfo()方法获取买家信息。

Customer接口见下。Customer通过buy()方法向Advertiser表明购买意愿。由于buy()方法设计消费者的具体偏好,因此此处并未给出具体的JML规格。

五、学习体会

总结而言,本单元学习了契约式编程的重要思想,并通过三次单元作业,掌握了读写JML规格语言的能力,能根据JML规格语言实现代码。就笔者而言,这是头一次涉及到多人合作完成代码的方法和思想,有非常独特的体验。

在完成单元作业方面,本单元确实难度较低,学习过程非常轻松愉快。同时,本单元间接帮助笔者回忆了离散数学和数据结构的一些相关知识。也只有在这种情况下,笔者才能意识到自己对于过去学过的知识遗忘之快,可见过去学习并不那么扎实。

最后,希望能顺利完成第四单元,继续加油!

标签:OO,结点,Group,测试数据,Person,回顾总结,query,单元
来源: https://www.cnblogs.com/syjzdkfc/p/16344802.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有