文章目录
大多数情况下,查询只关心根节点是谁,并不关心这棵树的形态,查询的时候,我们只要能判断两个节点的根节点是否相同即可
但是我们希望查询过程中,效率能稍微高一些。希望树能矮一点,这样我们从某个节点出发找根节点时,会更快速
假如当前的并查集如下,我们需要合并7和8所在树的根节点,我们从8出发找到根节点1,我们又从7出发经过相同的路径找到根节点1,然后我们发现根节点相同,不用合并,这样效率就很低了
优化find
我们进行如下优化:查询的时候将访问过的每个点的父节点修改成树根,这样的方法叫做路径压缩
由于无论是查询还是合并,我们都是操作根节点,修改后树变矮了,我们查找根节点更快,同时也不影响查询、合并的结果
查询的时候将访问过的每个点的父节点修改成树根,这样的方法叫做路径压缩
find执行以后,后面的查询效率就很好,但美中不足的是,第一次执行find的效率不高,这需要使用加权标记方法优化
加权标记(改进merge)
为什么会产生上图那么高的树呢?因为我们merge的时候,父子关系一直都是一个方向
对于以上的merge代码,我们如果按照如下的方式输入,并执行merge,就会产生图中的树
我们希望在构建并查集的过程中,进行集合合并的时候,能够使树能矮一点。我们使用加权标记的方式实现,使用一个height数组,记录每个节点的层高,下标则表示节点的编号
merge的时候,谁的height大,谁就作为父节点,由于我们只更新根节点的高度,在矮树挂在高树的情况下,根节点的高度不用更新
如果两棵树一样高,根节点合并以后,需要更新作为父亲的那棵树的根节点的height
再像上面一样输入,我们merge的时候,就能得到如下结构的并查集
用谁高谁当父亲的方式merge的时候,我们一直用单个节点往树中加入,这棵树一定只有两层
从单个节点开始构造并查集,使用谁高谁当父亲的方式merge,会得到两层的树。我们使用两个两层的树结合,两个根节点一样高,我们随便选取一个节点当父亲,更新该父节点的height即可(并不是更新所有节点的height),因为我们合并的时候只看根节点的高度。所以不是什么时候节点对应的height都是准的,可以保证的是,当前根节点的height是准的
比如我们按照如下的方式构造并查集,就会出现有的节点的height不准确
一般来说,在优化的merge中使用优化的find,在find的时候会改变树的结构,但find没有修改height,可能会导致当前根节点的height不准确,使用起来可能会不符合预期。所以我们不把merge加权优化和find优化放在一起使用