算法并查集的学习
用到的函数:
union_Vertices()//合并两个图的点集合
find_root()//找到一个集合的root
用到的数据逻辑表示:
int parent[Vertices];//parent[x] = y表示序号为x的结点的父节点是序号为y的结点
int rank[Vertices];//用于压缩路径 优化算法 避免成串的情况出现
int edges[Vertices][2];//描述边的集合
int find_root(int x, int parent[])函数的实现
int find_root(int x, int parent[]) {
int x_root = x; //初始化为当前结点
while (parent[x_root] != -1) { //一直向上寻找知道找到root结点
x_root = parent[x_root];
}
return x_root;
}
int union_vertices(int x, int y, int parent[], int rank[])函数的实现
int union_vertices(int x, int y, int parent[], int rank[]) {
int x_root = find_root(x, parent); // 找到x结点的root结点
int y_root = find_root(y, parent); // 找到y结点的root结点
if (x_root == y_root) return 0; // 两个若是同一root结点证明两个结点在同一集合内
//parent[x_root] = y_root;
//开始优化路径
if (rank[x_root] > rank[y_root]) { //x的集合的层数大于y的集合的层数时 要把y的集合向x的集合合并 反之合并的集合的rank会增加1
parent[y_root] = x_root;
}
else if (rank[x_root] < rank[y_root]) {//y的集合的层数大于x的集合的层数时 要把x的集合向y的集合合并 反之合并的集合的rank会增加1
parent[x_root] = y_root;
}
else { //两个集合的层数相同时,可选任意的一个结点为另外一个结点的父结点, 并让父节点的rank增加1
parent[y_root] = x_root; //这里选择把x_root的结点当做y_root结点的父节点
rank[x_root] ++;//父节点x_root 的rank[x_root]++;
}
return 1;//返回1说明成功合并两个不同的集合
}
完整代码:
#include <cstdio>
#include <stdlib.h>
#define VERTICES 6
/*
* Disjoint set 并查集
* 难点在于实现union过程
*/
void initialise(int parent[], int rank[]) {
int i;
for (i = 0; i < VERTICES; i++) {
parent[i] = -1;
rank[i] = 0;
}
}
int find_root(int x, int parent[]) {
int x_root = x;
while (parent[x_root] != -1) {
x_root = parent[x_root];
}
return x_root;
}
/* return 1 可以成功归并
return 0 不可以归并(已经在同一集合)
*/
int union_vertices(int x, int y, int parent[], int rank[]) {
int x_root = find_root(x, parent);
int y_root = find_root(y, parent);
if (x_root == y_root) return 0;
//parent[x_root] = y_root;
if (rank[x_root] > rank[y_root]) {
parent[y_root] = x_root;
}
else if (rank[x_root] < rank[y_root]) {
parent[x_root] = y_root;
}
else {
parent[y_root] = x_root;
rank[x_root] ++;
}
return 1;
}
int main() {
int parent[VERTICES] = { 0 }; // 用于表示结点的父节点
int rank[VERTICES] = { 0 };
int edges[6][2] = { // 类似邻接矩阵
{0, 1}, {1, 2}, {1, 3},
{2, 4}, {3, 4}, {2, 5}
};
initialise(parent, rank);
for (int i = 0; i < 6; i++) {
int x = edges[i][0];
int y = edges[i][1];
if (union_vertices(x, y, parent, rank) == 0) {
printf("Cycle detected.\n");
exit(0);
}
}
printf("No cycles found.\n");
return 0;
}