算法导论 第二十一章:不相交集合的数据结构

       不相交集合(Disjoint-set )数据结构保持一组不相交的动态集合S={S(1),S(2),...,S(k)}.每个集合通过一个代表(representative)来识别,即集合中的某个成员。设x表示一个对象,不相交集合支持操作:

MAKE-SET(x):建立一个新的结合,其唯一成员(也即代表)就是x。因为各集合是不相交的,故要求x没有在其他集合中出现过。

UNION(x,y):将包含x和y的动态集合合并成一个新的集合(即这两个集合的并集)。假定在这个操作之前两个集合是不相交的,操作之后,选取集合S(x)或S(y)的代表作为新代表。

FIND-SET(x):返回一个指向包含x的(唯一)集合的代表

不相交集合数据结构的一个应用:

确定一个无向图连通子图的个数。过程如下:

下面过程CONNECTED-COMPONENTS利用不相交集合操作来计算一个图的连通子图:

一旦CONNECTED-COMPONETS作为预处理步骤执行后,SAME-COMPONENT判断两个顶点是否在同一连通子图中:

不相交集合的链表表示

如合并的操作中,一种简单的操作方式是采用链表集合表示来实现,如下图:


利用链表结构实现上述应用的完整代码如下:

#include<iostream>
#include<string>
#include<cstdlib>
#include<vector>
#define N 256
using namespace std;

typedef struct setNode{
	char key;
	setNode *next;
	setNode *representative;
	setNode(char k):key(k),next(NULL),representative(NULL){}
	}setNode;

typedef struct Set{
	int num;
	setNode *head;
	setNode *tail;
	}Set;

typedef struct edge{
	char u;
	char v;
	}edge;

Set Make_Set(char k)
{
	setNode *x=new setNode(k);
	Set *s = new Set();
	s->head = x;
	s->tail = x;
	s->num  = 1;
	x->representative = x;
	return *s;
	}
setNode *Find_Set(Set s)
{
	return s.head->representative;
	}

void Update_Representative(setNode *head, setNode *representative)
{
	setNode *p=head;
	while(p != NULL)
	{ 
		p->representative = representative;
		p = p->next;
 		}
	}
void PrintSet(Set x)
{
	setNode *p = x.head;
	while(p != NULL)
	{  
		cout<<p->key<<"   ";
		p = p->next;
 		}
	cout<<endl;
	}
void Print_conComponents(Set LinklistSet[],int n)
{
	int count=1;
	for(int i=0; i<n; i++)
		if(LinklistSet[i].num != 0){
			cout<<"Connect component "<<count<<" is:";
			PrintSet(LinklistSet[i]);  
			count++;
			}
	   	}  
void Set_Union(Set &x,Set &y)
{
	 if (x.num < y.num){ 
		Set temp;
		temp = x;
		   x = y;
		   y = temp;
		}
	Update_Representative(y.head, x.head);
	x.tail->next = y.head;
	x.tail = y.tail;
	x.num += y.num;
	y.num  =0;
	}
void LinklistSet_Create(Set LinklistSet[],char vertex[],int vNum)
{
	for(int i=0;i<vNum;i++)
	{  
	    int index=(int)vertex[i];                  //eg.a->97,b->98,...
		LinklistSet[index] = Make_Set(vertex[i]);
	 	}  
	}

void Compute_conComponents(Set LinklistSet[],edge edgeArray[],int eNum)
{//Compute the component forest
	for(int i=0;i<eNum;i++)
	{
		Set *set_u = &LinklistSet[(int)edgeArray[i].u];   //use the pointer to change the LinklistSet[] info
		Set *set_v = &LinklistSet[(int)edgeArray[i].v];

		if (Find_Set(*set_u) != Find_Set(*set_v)){
			//Set_Union(LinklistSet[(int)edgeArray[i].u],LinklistSet[(int)edgeArray[i].v]);
			Set_Union(*set_u,*set_v);
			}
	
		}   
	}	
int main()
{
	char vertex[]={'a','b','c','d','e','f','g','h','i','j'};
	edge edgeArray[]={{'b','d'},{'e','g'},{'a','c'},{'h','i'},{'a','b'},{'e','f'},{'b','c'}};	
	int vNum=sizeof(vertex)/sizeof(char);
	int eNum=sizeof(edgeArray)/sizeof(edge);
	Set LinklistSet[N]={NULL};
	
	LinklistSet_Create(LinklistSet,vertex,vNum);           //link list set create
	Compute_conComponents(LinklistSet,edgeArray,eNum);    
	Print_conComponents(LinklistSet,N);

	return 0;
	}
运行结果:




【注:若有错误,请指点~~~~】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值