算法导论 第二十一章:不相交集合森林

        在不相交集合中的还有一种更快的实现中。用有根树来表示集合。

树中的每一个成员指向其父节点。每棵树的根包括了代表(representative),而且是他自己的父节点。不相交森林即由多棵这种树组成,例如以下图所看到的:

[注:(b)是(a)UNION(e,g)的结果]

採用上述表示方法直观上并不比採用链表表示算法更快。可是能够通过“按秩合并”和“路径压缩”来提升效率。

按秩合并(union by rank)

    对于每一个节点,用秩表示节点高度的一个上界。

在按秩合并中,具有较小秩的跟在UNION操作中要指向具有较大秩的根。

路径压缩(path compression):

   在FIND-SET操作中,利用这样的启示式策略来使查找路径上的每一个节点都直接指向根节点。(路径压缩不改变节点的秩)


相关操作伪代码例如以下:

     须要说明的是。上述FIND-SET过程採用一种两趟方法(two-pass method):一趟是沿查找路径上升。直到根;第二趟是沿查找路径下降,以便更新每一个节点。使之直接指向根。


不相交森林实现连通子图的完整代码例如以下:

#include<iostream>
#include<string>
#include<cstdlib>
#include<vector>

using namespace std;

typedef struct setNode{
	char key;
	int rank;
	setNode *parent;
	setNode(char k):key(k),rank(0),parent(NULL){}
	}setNode;

typedef struct Set{
	setNode *root;
	}Set;

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

setNode *Make_Set(char k)
{
	setNode *x=new setNode(k);
	x->parent = x;
	return x;
	}

setNode *Find_Set(setNode *x)
{
	if(x != x->parent)
		x->parent=Find_Set(x->parent);
	return x->parent;
	}
void Link(setNode *x,setNode *y)
{
	if(x->rank > y->rank)
		y->parent = x;
	else
	{ 
		x->parent = y;
		if(x->rank == y->rank)
			y->rank = y->rank + 1;
		}
	}
void Set_Union(setNode *x,setNode *y)
{
	Link(Find_Set(x),Find_Set(y));
	setNode *z=Find_Set(x);
	}
void forestSet_Create(Set forestSet[],char vertex[],int vNum)
{
	for(int i=0;i<vNum;i++)
	{ 
	    int index=(int)vertex[i];                  //eg.a->97,b->98,...
		forestSet[index].root = Make_Set(vertex[i]);
		}
	}
void Compute_conComponents(Set forestSet[],edge edgeArray[],int eNum)
{//Compute the component forest
	for(int i=0;i<eNum;i++)
	{
		setNode *set_u=forestSet[(int)edgeArray[i].u].root;
		setNode *set_v=forestSet[(int)edgeArray[i].v].root;
		if (Find_Set(set_u) != Find_Set(set_v))
			Set_Union(set_u,set_v);
		} 
	}
void Print_conComponents(Set forestSet[],char vertex[],int vNum)
{//classify the forest and print the connect components and the representative
	string representative;
	for(int i=0;i<vNum;i++){
		setNode *t;
		t=Find_Set(forestSet[(int)vertex[i]].root);		
		if(representative.find(t->key) == -1)     //the char t is not in representative 
			representative += t->key;
		}
	cout<<"The representative of the forest:"<<representative<<endl;
	
	int repLen=representative.length();
	vector<char> *ComponentsVec = new vector<char>[repLen];
   for(int i=0; i<vNum; i++)
   {	 
		setNode *temp;
		temp=Find_Set(forestSet[(int)vertex[i]].root);
		int index=representative.find(temp->key);
		ComponentsVec[index].push_back(vertex[i]);
		}	    

   for(int i=0; i<repLen; i++)
	{
		cout<<"The connect component "<<i+1<<" is:";
		for(int j=0; j<ComponentsVec[i].size(); j++)
			cout<<ComponentsVec[i].at(j)<<"   ";
		cout<<endl;
		} 
	}
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 forestSet[256]={NULL};

	forestSet_Create(forestSet,vertex,vNum);           //Create forest set
	Compute_conComponents(forestSet,edgeArray,eNum);   //Computing the component forest
	Print_conComponents(forestSet,vertex,vNum);
	
	return 0;
	}
执行结果:



【注:若有错误。请指正~~~】


原文地址:https://www.cnblogs.com/jzssuanfa/p/7101447.html