并查集--Disjoint Set

算法并查集的学习

用到的函数:

  • 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;

}
posted @ 2020-04-06 18:06  DengSchoo  阅读(193)  评论(0编辑  收藏  举报