BUAA OO Unit3

前言

第三单元的作业可以简单,但也可以非常复杂。如果没有性能的限制,想必大家都可以根据给出的规格,简单地实现相应的功能。但是如果想要追求性能,加上算法的实现,本单元的作业还是具有相当大的挑战的。本单元用到的主要算法由并查集算法和单源点最短路径算法

一、关于测试

首先浅谈一下我对黑盒测试和白盒测试的理解,黑盒测试相当于把程序的代码装进一个黑盒子里,测试者是不知道代码的具体实现过程的,只能根据输入和输出来判断程序是否正确。而白盒测试则相当于在用逻辑来测试程序的正确性,通过对代码的逻辑进行分析,然后再根据一些相对特殊的情况,检测代码实现的正确性。

因为我没有写数据生成器,所以本单元的测试方式主要还是“白盒”测试,这种测试可以虽然可以检测逻辑上的正确性,但是由于我对于性能的计算方法所知甚少,所以经常会出现性能上的问题。

二、bug分析

hw9

本次作业的bug(也不能说是bug)主要是CTLE,问题就在于我的架构没有用算法,而是简单的一个循环,将代码改为并查集的算法之后,就可以通过测试。

hw10

这次作业的bug较多,首先是query_group_value_sum这个函数中,我对JML的理解出现了偏差,导致除以size的位置错误,所以出现了一个WA的点,其他的点都是CTLE,原因在于我又没有使用并查集的算法。然而在debug的过程中,我依然出现了很多的CTLE的地方,问题在于,我对于modigyRelation的过程中的动态维护出现了问题。

hw11

本次作业的主要问题还是qlm指令的性能问题,因为这个问题,我有三个CTLE,经过分析发现,我性能出现问题的原因在于,每次qlm时,我都需要进行两次判断是否具有关系,其中一次判断还需要两次树的重建,这就严重影响了我的性能。

三、架构设计

首先是根据指导书的要求,新建一个计数器类,同时在所有的异常类中都创建一个类的对象,用于在每次异常发生时记录异常的次数,同时进行输出。此后的所有异常类都不在复述。  

hw9

 

第九次作业比较简单,只有两个主要的类MyPerson和MyNetwork,对于人与人之间的处理比较简单,只有增加关系,判断是否有关系、获取关系三角形的总和、获取两个人之间的值,以及共有几组互不相干的人。处理这些问题的方法也比较简单,对于数据存储的方法是在MyPerson类中添加acquaintance属性和value属性来记录两个人之间的关系。添加father来连接所有有关系的人。

虽然大家都会用到并查集的思路,我的思路和很多人也都一样,但我还是再写一下我用的并查集的大致思路。

最终的目标是得到一个森林,森林中的每棵树表示一组有关系的人,处于不同树中的人没有关系。为了得到这样的一棵树,就需要在addRelation 的过程中进行动态维护。我们利用在MyPerson类中添加的father属性来实现这一目的。在每次addPerson时,都将当前person 的father设为其本身,在addRelation的时候,判断两个人是否处于同一个树上(具体方法后续说明),如果两个人本身就处于同一棵树上,那么说明他们本身就有关系,而我们的目的就是利用这样的一棵树来表示所有有关系的人,所以此时就不需要做任何处理,但如果两个人不在一棵树上,就说明这两个人之前没有关系,但现在需要添加关系,在这两个人添加完关系之后,这两颗树上所有的人之间都有关系了,如何才能让这两棵树上所有的人之间都有关系呢(后续说明)。

先说如何将两个没有关系的人之间加上关系:只需要将其中一个人所在的树与另一个人所在的树相连,一个比较简单的方法是,将一个人的祖先的father设为另一个人的祖先。

然后怎么判断两个人之间是否有关系:很显然,只需要判断两个人的祖先是否是同一个人。

至此,第九次作业中的获取数据的函数都可以通过并查集+动态维护变量(treeCount、tripleCount)得出。

hw10

 

本次作业新增了两个类,一个MyGroup,一个MyMessage, 人与人之间的操作也不仅限于是否存在关系,而是增加了消息发送的功能。同时,在计数问题上,新增了与bestAcquaintance有关的问题。在人与人之间的关系的操作上,新增了modifyRelation的操作,所以可能会出现删除关系的情况。对于bestAcquaintance的更新要在relation变化时进行动态维护,而不能在最终的函数中遍历,否则会超时。

本次作业依然需要使用到并查集,但是在删除关系时的操作比较复杂,因为并查集没有删边操作,所以每次只能重新构建树。但是依据什么重建呢,我们必须新建一个数据结构,用来动态储存人与人之间的关系,每次删除关系时,要根据这个数据结构中存储的关系来重新建树,并动态维护所需要的数据。

对于消息的发送以及其他的函数的实现只需要按照规格进行书写即可。

大致思路如下:

Hashmap relation = new Hashmap<Interger, ArrayList<Interger>>;
addRelation() {
    //更新relation
    //同时更新现有的树
}
modifyRelation() {
    if (要删除关系) {
        //更新relation
        //根据relation重新建树,并动态维护变量。
    }
}

hw11

 

新增了三个特殊的Message类,用来发送不同的消息,本次实验的难点不在此处,对于不同message的处理只需要按照规格书写即可。

本次实验的难点在与queryLeastMoments函数的书写,这个函数需要找到从某一个人出发经过至少两个其他的不同的人回到自己本身的最短路径,要找最短路径,就需要用到迪杰斯特拉算法。我实现这一函数的具体方法如下:

//1、找到所有与person有关系的人存到一个新的数组里:ArrayList dijktraPeople = new ArrayList<People>;
//2、遍历person的acquaintance,将每个acquaintance[i]都当作一次终点;(因为person和这个人是有直接关系的,所以如果在删除他们之间的直接关系之后,他们之间仍有联系,那就说明,存在一个由person到person的环;
//3、
if(有环) {
	//调用迪杰斯特拉算法,求出从person到acquaintance[i]的最短路径;
    //然后,加上他俩之间原来的权重,就是这个环的最小权重;
    //求出所有环当中权重最小的,就是要求的leastMoment;
}

四、关于OK测试方法

对于OKTest的理解在于,他仅仅是为了测试代码的实现是否真的满足了规格,这是为了能够检验我们写的程序所实现的功能能不能达到程序设计者心目中的要求。这个过程是确保,程序设计者设计的规格所实现的功能是否与其心中所想的功能一致。

在我们的实验中,满足规格的实现,正常来说都能实现设计者心中的功能,而我们作为实现者,我们写的代码只有通过OkTest的测试之后,才能说其实现了相应的功能。

五、本单元学习体会

本单元最大的难点就在于图模型的构建与维护,采用什么样的算法,在算法的实现过程中用什么样的数据结构来实现都是需要思考的。当然,本实验原本的难点应该是规格的理解,与基于规格的代码实现,这一部分如果仅仅是根据规格简单书写代码也是很好实现的,但是如何在理解规格的基础上,解析其实质性的功能,并通过高性能的算法进行实现就具有相当大的难度。所以我每次作业都会因为性能原因T掉好多个点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值