C++实现并查集

将N个不同的元素分成一组不相交的集合。
开始时,每个元素就是一个集合,然后按规律将两个集合进行合并。

假如已知有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属于一个另朋友圈,结果为两个朋友圈。

最后请分析所写代码的时间、空间复杂度。  

这个题用利用并查集实现会比较简易和高效!

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stdlib.h>
using namespace std;

class UnionFindSet
{
public:
	UnionFindSet(size_t size)
		:_array(new int[size])
		, _size(size)
	{
		memset(_array, -1, sizeof(int)*_size);
	}
	~UnionFindSet()
	{
		if (_array != NULL)
		{
			delete[] _array;
		}
	}
	void Merge(int root1, int root2)
	{
		while (_array[root2] >= 0)
		{
			root2 = _array[root2];

		}
		while (_array[root1] >= 0)
		{
			root1 = _array[root1];
		}
		_array[root1] += _array[root2];
		_array[root2] = root1;
	}
	int Find(int child)
	{
		while (_array[child] >= 0)
		{
			child = _array[child];
		}
		return child;
	}
	void print()
	{
		for (int i = 0; i < _size; ++i)
		{
			cout << _array[i] << " ";
		}
		cout << endl;
	}
	int friends(int n, int m, int r[][2])
	{
		UnionFindSet uf(n + 1);
		for (int i = 0; i < m; i++)
		{
			int first = r[i][0];
			int second = r[i][1];
			uf.Merge(first, second);
		}
		uf.print();
		int count = 0;
		for (int i = 1; i <= n; i++)
		{
			if (uf._array[i] < 0)
			{
				count++;
			}
		}
		return count;
	}
private:
	int*  _array;
	size_t _size;
};
void test()
{
	UnionFindSet us(10);
	us.Merge(0, 6);
	us.Merge(0, 7);
	us.Merge(0, 8);

	us.Merge(1, 4);
	us.Merge(1, 9);

	us.Merge(2, 3);
	us.Merge(2, 5);

	us.Merge(0, 4);
	us.print();
	cout << "4的朋友树的父节点是" << us.Find(4) << endl;
	

	int n = 5;
	int m = 3;
	int r[][2]= { { 1, 2 }, { 2, 3 }, { 4, 5 } };
	int Frindcirle = us.friends(n, m, r);
	cout << Frindcirle << endl;
}

int main()
{
	test();
	system("pause");
	return 0;
}



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值