并查集的代码实现
并查集主要由三部分接口函数构成,分别是findhead(),union_set()和Is_sameset()构成。findhead主要是用来寻找同集合中的头集合,union_set主要是用来合并两个集合,is_Sameset主要是判断两个数据是否是同一个集合。
unionset的构造
class UnionFindSet {
vector<int> parent; // 用来存放它的上层节点
vector<int> rank; // 存放根节点的尺寸,用深度来表示
public:
UnionFindSet(vector<int>& vec);
int findhead(int nums);
void union_set(int node1, int node2);
bool isSameset(int num1, int num2);
};
UnionFindSet::UnionFindSet(vector<int>& vec) { //初始化
for (auto& it : vec) {
parent[it] = it; //初始化父路径
rank[it] = it; //初始化秩
}
}
parent用来存放子节点的头结点head,初始化的是否每一个child节点的parent节点都是自己本身。
findhead函数
找到节点的最终父节点,并且进行路径压缩,使得所有的子节点直接指向父节点,这样就可以大大提高子节点寻找父节点的效率。
int UnionFindSet::findhead(int num) { //查找根节点,也就是它的老大,并且压缩路径,压缩到只有一层
int child = num;
while (parent[num] != num) { //此循环退出时,num是根节点
num = parent[num];
}
while (child != num) { //再走一遍上面的过程。
int par = parent[child]; //保存父节点
parent[child] = num; //child的父节点指向num;
child = par;
}
return num;
}
合并两个数到同一个集合中
void UnionFindSet::union_set(int node1, int node2) {
int Pa1 = findhead(node1);
int Pa2 = findhead(node2);
if (Pa1 == Pa2) return;
if (rank[Pa1] > rank[Pa2]) {
parent[Pa2] = Pa1; //合并Pa2到Pa1
}
else if (rank[Pa1]<rank[Pa2]){
parent[Pa1] = Pa2;
}
else {
parent[Pa1] = Pa2;
rank[Pa2] += 1;
}
}
首先通过调用findhead找到头结点,然后根据节点的秩的不同来合并两个节点。
全部代码
!= num) { //此循环退出时,num是根节点
num = parent[num];
}
while (child != num) { //再走一遍上面的过程。
int par = parent[child]; //保存父节点
parent[child] = num; //child的父节点指向num;
child = par;
}
return num;
}
void UnionFindSet::union_set(int node1, int node2) {
int Pa1 = findhead(node1);
int Pa2 = findhead(node2);
if (Pa1 == Pa2) return;
if (rank[Pa1] > rank[Pa2]) {
parent[Pa2] = Pa1; //合并Pa2到Pa1
}
else if (rank[Pa1]<rank[Pa2]){
parent[Pa1] = Pa2;
}
else {
parent[Pa1] = Pa2;
rank[Pa2] += 1;
}
}
int main() {
vector<int> vec{ 1,2,3,4,5,6,7 };
UnionFindSet ufset(vec);
ufset.union_set(1, 2);
ufset.union_set(1, 3);
cout << "2的父亲是" << ufset.findhead(2) << endl;
system("pause");
}