数据结构与算法分析-C++描述 第8章 不相交集类(disjointSet)

背景介绍(background):

       等价关系(equivalence relation):是满足下列三个性质的关系R:

               1)自反性:对所有的a\in S, a \ R \ a;(其中R表示关系);

               2)对称性:a \ R \ b 当且仅当b\ R \ a;   

               3)传递性:若a \ R \ bb \ R \ ca\ R \ c

               举例: a \leq b不具有等价性;电气连通性具有等价性。

       输入数据最初是N个集合的类(collection),每个集合含有一个元素,初始的所有关系均为false(除自反性),每个元素都有一个不同的元素,从而S_i \ \cap \ s_j = \o,这使得这些元素不相交;

不相交集类(disjointSet):

        不相交集类是将一些元素合并为不相交的各个集合,在同一个集合中的元素两两等价,不同集合中的元素不等价。此时,有两种操作是允许的:

        find:返回给定元素的集合的名字;

        union:如果想添加关系a \sim b,首先看二者是否存在关系(这可通过find检测二者是否在同一个类中),如果二者不在同一类中则对二者做union操作,将二者合并为一个新的等价类;

       该算法是动态的,因为在算法的执行过程中,集合可以通过union改变而改变。

动态等价性问题解决方案:

        1)保证指令find能够以常数最坏情形运行时间运行;

        2)保证指令union能够以常数最坏情况运行时间运行;

       已经证明二者不能同时以常数最坏情况运行时间运行;

基本数据结构:

数据结构与算法分析-C++描述 第8章 不相交集类(disjointSet)_第1张图片

        

数据结构与算法分析-C++描述 第8章 不相交集类(disjointSet)_第2张图片

       

数据结构与算法分析-C++描述 第8章 不相交集类(disjointSet)_第3张图片

 

数据结构与算法分析-C++描述 第8章 不相交集类(disjointSet)_第4张图片

非显示表示结果: 

数据结构与算法分析-C++描述 第8章 不相交集类(disjointSet)_第5张图片

 灵巧求并算法:

        1)按大小求并:对其进行简单的改进是借助任意的方法打破现在的随意性,使得总是较小的树成为较大的树的子树。为了实现按大小合并的方法,需要记住每棵树的大小,可以让每个根元素包含它的树的大小的负值。合并的时候首先检查树的大小,将较小的树成为较大树的子树,新的树的大小为两棵树大小的和。

数据结构与算法分析-C++描述 第8章 不相交集类(disjointSet)_第6张图片

        2)按高度求并: 跟踪每棵树的高度而不是大小并执行合并使得浅的树成为深的树的子树。只有两棵深度相等的树求并的时候树的高度才增加(树的深度加1),为了实现按高度求并,需要记住每棵树的高度,可以让每个根元素包含它的树的高度的负值。只有合并的两棵树高度相等的时候才需要更新树的高度(根元素的值减去1)。

按大小求并和按高度求并的非显示表示(根节点的“更新”准则不同,其他节点性质一致):

数据结构与算法分析-C++描述 第8章 不相交集类(disjointSet)_第7张图片

不相交类实例: 

//disjointSet.cpp
#include
#include
#include

using namespace std;

class DisjointSet{
public:
	//DisjointSet constructor
	explicit DisjointSet(int n);
	
	//find value operation
	int find(int value) const;
	
	//union root2 to root1
	void unionSet(int root1, int root2);
	
	//union root2 to root1 by size
	void unionSetBySize(int root1, int root2);
	
	//union root2 to root1 by height
	void unionSetByHeight(int root1, int root2);
	
	//print the result
	void print();
	
	//reallocate s
	void init(){
		for(int i = 0; i < s.size(); i++){
			s[i] = -1;
		}
	};
private:
	vector s;
};

DisjointSet::DisjointSet(int n = 10):s(n){
	for(int i = 0; i < n; i++){
		s[i] = -1;
	}
}

int DisjointSet::find(int value) const{
	if(s[value] == -1){
		return value;
	}else{
		return find(s[value]);
	}
}

void DisjointSet::unionSet(int root1, int root2){
	s[root2] = root1;
}

void DisjointSet::unionSetBySize(int root1, int root2){
	if(s[root2] < s[root1]){	//size root2 is larger
		s[root2] += s[root1];
		s[root1] = root2;
	}else{ 						//size root1 is larger
		s[root1] += s[root2];
		s[root2] = root1;
	}
}

void DisjointSet::unionSetByHeight(int root1, int root2){
	if(s[root2] < s[root1]){			//root2 is deeper
		s[root1] = root2;
	}else if(s[root2] == s[root1]){		//the height is same
		s[root1]--;
		s[root2] = root1;
	}else{								//root1 is deeper
		s[root2] = root1;
	}
}

void DisjointSet::print(){
	cout << " the disjointSet info as follow " << endl;
	for(typename vector::iterator itr = s.begin(); itr != s.end(); ++itr){
		cout << setw(4) << *itr << " ";
	}
	cout << endl;
	for(int i = 0; i < s.size(); i++){
		cout << setw(4) << i << " ";
	}
	cout << endl;
}

int main(){
	cout << "simple disjointSet : " << endl;
	DisjointSet disjointSet(8);
	disjointSet.unionSet(4, 5);
	disjointSet.unionSet(6, 7);
	disjointSet.unionSet(4, 6);
	disjointSet.unionSet(3, 4);
	disjointSet.print();
	/*for(int i = 0; i < disjointSet.s.size(); i++){
		cout << disjointSet.find(i) << " ";
	}
	cout << endl;*/
	
	cout << "union disjointSet by size : " << endl;
	disjointSet.init();
	disjointSet.unionSetBySize(4, 5);
	disjointSet.unionSetBySize(6, 7);
	disjointSet.unionSetBySize(4, 6);
	disjointSet.unionSetBySize(3, 4);
	disjointSet.print();
	/*for(int i = 0; i < disjointSet.s.size(); i++){
		cout << disjointSet.find(i) << " ";
	}
	cout << endl;*/
	
	cout << "union disjointSet by height : " << endl;
	disjointSet.init();
	disjointSet.unionSetByHeight(4, 5);
	disjointSet.unionSetByHeight(6, 7);
	disjointSet.unionSetByHeight(4, 6);
	disjointSet.unionSetByHeight(3, 4);
	disjointSet.print();
	/*for(int i = 0; i < disjointSet.s.size(); i++){
		cout << disjointSet.find(i) << " ";
	}
	cout << endl;*/
	
	cout << "done . " << endl;
	return 0;
}

 运行结果:

simple disjointSet : 
 the disjointSet info as follow 
  -1   -1   -1   -1    3    4    4    6 
   0    1    2    3    4    5    6    7 
union disjointSet by size : 
 the disjointSet info as follow 
  -1   -1   -1    4   -5    4    4    6 
   0    1    2    3    4    5    6    7 
union disjointSet by height : 
 the disjointSet info as follow 
  -1   -1   -1    4   -3    4    4    6 
   0    1    2    3    4    5    6    7 
done . 

practice makes perfect !

你可能感兴趣的:(C++,数据结构与算法分析-C++描述)