并查集(Union-Find)

在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题。有一个联合-查找算法union-find algorithm)定义了两个用于此数据结构的操作:

  • Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
  • Union:将两个子集合并成同一个集合

问题:

假如已知有n个人和m对好友关系(存于数字r)。如果两个人是直接或间接的好友(好友的好友的好友…),则认为他们属于同一个朋友圈,请写程序求出这n个人里一共有多少个朋友圈。假如:n = 5,m = 3,r = {{1 , 2} , {2 , 3} , {4 , 5}},表示有5个人,1和2是好友,2和3是好友,4和5是好友,则1、2、3属于一个朋友圈,4、5属于另一个朋友圈,结果为2个朋友圈。


并查集森林是一种将每一个集合以表示的数据结构,其中每一个节点保存着到它的父节点的引用,例如对于本题目

并查集的实现可以理解成森林。每一个下标对应是是一棵树。在这里我们用可以用一个数组来表示这个森林,而根节点的内容我们认为都是-1。所以,默认的整个数组数值都为-1。即初始化为:


并查集(Union-Find)_第1张图片


具体实现过程:

并查集(Union-Find)_第2张图片实现代码:

#pragma once
#include
#include
using namespace std;

class UnionSet {
public:
	UnionSet(int n)
	{
		_v.resize(n + 1, -1);
	}
	//n个人 m对关系  
	int Find(int index)
	{
		int root = index;

		while (_v[root]>=0)
		{
			root = _v[root];
		}
	
		return root;
	}

	void Merge(int n,int m, int r[][2])
	{
		for (int i = 0; i < m; i++)//合并两个集合  
		{
			//找到真正的根 对根操作
			int root1 = Find(r[i][0]);
			int root2 = Find(r[i][1]);

			if (root1 != root2)
			{
				//合并两个集合
				_v[root1] += _v[root2];
				_v[root2] = root1;
			}
			
		}
	
	}
	int CountSet()
	{
		int count = 0;
		for (size_t i = 1; i < _v.size(); i++)
		{
			if (_v[i] < 0)
				count++;
		}
		return count;
	}
private:
	vector _v;
};
void TestUnionSet()
{
	
	int n = 5;
	int m = 3;
	int r[][2] = { {2,1},{3,2},{4,5 } };
	UnionSet u(n);
	u.Merge(n, m, r);
	int count = u.CountSet();
	cout << count << endl;
	int i = 0;
}


你可能感兴趣的:(数据结构)