利用双亲表示法可以追溯到某个节点所在的树的根节点
结构
利用线性表存储,每个节点含一个==data==域,一个==parent==域,若用的是顺序表存储且所有节点的data是递增的,可以直接用==数组下标==表示数据,省去data域
parent域就是指向这个节点的父节点在数组中的下标
根节点的parent域设置为==负数==(如-1)
struct TreeNode{
DataType data;
int parent;
}
TreeNode nodes[MaxSize];
查找根节点
- 沿着parent域追溯到某个parent域为负的节点,该点就是根节点
- 假设给定了需要查找根节点的节点的下标为i
int findRoot(int i,TreeNode nodes[]){
while(nodes[i].parent>=0){i=nodes[i].parent};
return i;
}
合并两个集合
- 先查找这两个节点(下标为p,q)所在的==集合==是否是同一个,即是否是同一个==根节点==
- 若是同一个集合,不做任何操作,否则将一个集合的根节点合并到另一个集合的根节点上,即修改==parent域==
void Union(int p,int q,TreeNode nodes[]){ //注意union是C关键字
if(findRoot(p)!=findRoot(q))nodes[q].parent=p;
}
Union的优化
为了尽可能地降低union带来的树的高度增加的影响(合并后的==查找性能==),可以将规模(总节点个数)小的树合并到规模大的数上
将根节点的parent设置为该集合所有节点个数的==相反数==
另一种思路是将高度小的合并到高度大的树上
对集合的规模的维护:
- 在合并的时候,合并后的集合需要将合并前的两个集合的规模数相加
void union(int p,int q,TreeNode nodes[]){
int root1=findRoot(p);
int root2=findRoot(q);
if(nodes[root1].parent<nodes[root2].parent){ //因为都是负的所以是前者的绝对值大于后者
nodes[root1].parent+=nodes[root2].parent; //合并规模数
nodes[root2].parent=root1; //root2合并到root1上
}
else {
nodes[root2].parent+=nodes[root1].parent;
nodes[root1].parent=root2;
}
}