不相交集的find和union

两个不相交集合是指S1 ∩ S2 == {}空集,一般包含两个操作,find和union操作

find:返回包含给定元素的集合

union把两个集合合并成一个集合


不相交集合的数组表示法,

第一个解法是用一个数组存储一int值,

如果结点为根,则为树的高度的负值-1,(因为初始为-1);如果为非根结点,则存储父结点下标

第二个解法思路也是一样,只不过数组存储的是一个结点结构,包括data值,包括p父节点,rank结点的秩,代表x的高度(从x到某一后代结点的最长简单路径上边的数目)的上界。

MakeSet:创建一个单元素集合,并且初试时秩为0

FindSet:不改变任何秩,也是采用数据压缩的解法,这种解法使查找路径中的每个结点直接指向根。

UininSet:如果根没有相同的秩,则让较大秩的根成为较小秩的根的父节点,秩保持不变

                   如果根有相同的秩,则任意选择两个根中的一个作为父节点,并使它的秩加1

第一种:

#include <iostream>
#include <vector>
using namespace std;

class DisjSets
{
public:
	explicit DisjSets (int numElements) : s(numElements)
	{
        for (int i = 0; i < s.size(); i++)
            s[i] = -1;
	}

	int find(int x) const
	{
		if (s[x] < 0)
			return x;
		else
			return find(s[x]);
	}

	/************************************************************************/
	/*返回包含x的集合,如果是根结点,返回本身,如果存在父节点,返回父节点
	  使用路径压缩的find,效果是从x到根的路径上的每一个
	  结点使它的父节点变成根,即使得路径上的每个s[x]等于
	  find(s[x])找到的父结点,实现了路径压缩(使路径上的每个结点的路径减少了)*/
	/************************************************************************/
	int find(int x)
	{
		if (s[x] < 0)
			return x;
		else
			return s[x] = find(s[x]);
	}

	//按高度求并, 使浅的树成为深的树的子树,
	//当两棵相等的树求并时树的高度才增加1
	void unionSets(int root1, int root2)
	{
		//root2更深一些,使root2成为新结点
        if (s[root2] < s[root1])
            s[root1] = s[root2];
		else
		{
			if (s[root1] == s[root2])
			    s[root1]--;
			s[root2] = root1;
		}
	}

private:
	//存储每个子树的高度,如果是根节点,则存储高度
	//实际上存储的是高度的负值,减去附加的1,初试时所有的项都是-1
	//不是根节点则存储父节点的序号
	vector<int> s;
};

int main()
{
	DisjSets dset(10);

	int root1, root2;
	cout << "请输入1-10之间的数:" << endl;
    while (cin >> root1 >> root2)
         dset.unionSets(root1, root2);
	cout << root1 << "的根是:" << dset.find(root1) << endl;
	cout << root2 << "的根是:" << dset.find(root2) << endl;

	system("pause");
    return 0;
}

运行结果为:



第2种:运行结果是按照算法导论第三版 329中简单的图

#include <iostream>
#include <vector>
using namespace std;

template <typename DataType>
struct ArrayNode  
{
	DataType data;
    ArrayNode *p;           //结点的父亲
	int rank;        //结点的高度
	ArrayNode() : p(NULL), rank(0) {}
};

template <typename DataType>
class ArraySet
{
public:
	typedef ArrayNode<DataType> Node;
	ArraySet(int num) : number(num)
	{

	}

	//使每个结点成为一个单独的集合
	void MakeSet()
	{
		cout << "请输入 " << number << "个数据:" << endl;
		for (int i = 0; i < number; i++)
		{
			DataType val;
			cin >> val;
			Node *nd = new Node;
			nd->p = nd;
			nd->rank = 0;
			nd->data = val;
			vec.push_back(nd);
		}       
	}

	Node *getNode(int i)
	{
		return vec[i-1];
	}

	//带路径压缩的找到x所在的集合
	Node* FindSet(Node *x)
	{
        if (x->p != x)
			x->p = FindSet(x->p);
		return x->p;
	}

	//合并集合,将rank值较小的集合合并到rank值较大的集合
	void UnionSet(Node *nx, Node *ny)
	{
		Node *x = FindSet(nx);
		Node *y = FindSet(ny);
		if (x->rank > y->rank)
			y->p = x; 
		else
		{
			x->p = y;
			if (x->rank == y->rank)   //当两者的rank相同,则使树根的rank增加1
				(y->rank)++;
		}
	}

	void display()
	{
	    for (int i = 0; i < number; i++)
		{
			cout << "第 " << i+1 << " 个结点的数据为:" << vec[i]->data 
				<< " 父节点为:" << vec[i]->p->data << " 秩为:" << vec[i]->rank << endl;
		}
		cout << "*************************************************" << endl;
	}

	~ArraySet()
	{
		for (int i = 0; i < number; i++)
		{
            delete vec[i];
			vec[i] = NULL;
		}
	}

private:
    vector<Node *> vec;
	int number;
};

int main()
{
	ArraySet<char> as(6);
	as.MakeSet();
	as.UnionSet(as.getNode(1), as.getNode(2));
	as.UnionSet(as.getNode(3), as.getNode(4));
	as.UnionSet(as.getNode(5), as.getNode(6));
	as.display();
	as.UnionSet(as.getNode(2), as.getNode(4));
	as.display();
	as.UnionSet(as.getNode(4), as.getNode(6));
	as.display();

	system("pause");
	return 0;
}

运行结果:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值