回忆上一次文章中,Union操作并没有规定具体让哪棵树成为为另一棵树的子树。由此可以看出,该Union操作是任意的,我们如果想要对数据进行寻找等操作就会显得无迹可寻。同时,该方法的合并并没有合并到一棵树的根节点上,思考:当合并到原本的树的最深的节点时,合并后的深度无疑为大大增加,这样就会使得后续的 Find 和 Union 花费更多的时间。因此,出现了两种改进该Union的方法。
其一、按大小求并(union-by-size)。顾名思义,该方法将含有节点的数目更少的树合并另一棵到根节点上。
对于这种方法,有结论:如果Union都是按大小进行的(即从开始,所有树的深度都为0起的Union),那么任何节点的深度不会超过logN。
证明:先注意节点初始处于深度为0的位置,当其深度随着Union增加时,节点被置于至少是它以前所在树的两倍大的一棵树上。因为另外一棵作为合并后的树的原始大小必然是大于该节点所处于的树的。同时要考虑到从一开始这些树就进行了Union操作,满足Union的这些性质,因此对于总元素大小为N的数组,任意节点的深度最多可以增加log N。同时,在这种情况下,最坏的树类似于二项队列。
现在考虑这种方法的实现。由于其按大小求并的性质,我们需要记住每一棵树的大小。由于我们所拥有的仅仅为一个存储着元素的数组,所以我们可以让 根节点存储该棵树的大小的负值,同时其他的树叶与上述的相同,存储其父节点的数组下标。
在以上的方法的前提下,实现该方法仅仅需要在原来的基础上增加一道 if 函数