用于不相交集合的操作
一个不相交集合的数据结构维护了一个不相交动态集的集合 S={s1, s2, s3,....},其中的s1,s2,s3都是集合.我们用一个代表来标识每个集合,该代表为该集合的某个成员.
makeSet():建议一个新的集合,它的成员都是s1, s2, s3中的代表.由于s1, s2 s3...是不相交的集合因此它的成员是不会有重复的。
unionSet(x, y):将包含x, y的两个集合(sx, sy)合并成一个新的集合,即这两个集合的并集.
findSet(x): 返回一个成员,这个元素为包含x的集合的代表.
#include <iostream>
#include <type_traits>
#include <memory>
template<unsigned int N, unsigned int M>
class SetData{
private:
int (&array)[N][M];//这里必须是一个引用
int* A; //A是array这个总的集合中各个子集合的代表.
int* B; //B相当于是总集合中每个子结合中元素的个数.
int count;
void makeSet(const int& x);//建立一个新的集合(A),他的唯一成员是x
int findSet(const int& x);
void unionSet(const int& x, const int& y);
void link(const int& x, const int& y);//将集合x和集合y合并成一个新的集合.
public:
SetData(int (&refArray)[N][M]);
~SetData();
int connectedComponent();
};
template<unsigned int N, unsigned int M>
SetData<N, M>::SetData(int (&refArray)[N][M])
:array(refArray),
A(nullptr),
B(nullptr),
count(0)
{
//constructor function;
if(N != M){
throw std::bad_cast();
}
//std::cout<<"success"<<std::endl;
this->A = new int[100];
this->B = new int[100];
std::uninitialized_fill_n(this->A, 100, 0);
std::uninitialized_fill_n(this->A, 100, 0);
}
template<unsigned int N, unsigned int M>
SetData<N, M>::~SetData()
{
if(this->A != nullptr){
delete[] this->A;
this->A=nullptr;
}
if(this->B != nullptr){
delete[] this->B;
this->B=nullptr;
}
}
template<unsigned int N, unsigned int M>
int SetData<N, M>::connectedComponent()
{
int i=0;
int j=0;
int tempCount=0;
for(; i<N; ++i){ //这里假定所有集合都是不相交的因此有N个集合,把这N个集合放到一个数组A中.
this->makeSet(i); //这里通过makeSet给SetData中的数组A,B进行初始化.(不要忘了A是array中各个子集代表的集合,B则对应着array中各个子集的个数)
}
for(i=0; i<N; ++i){ //逐个访问集合中的元素.
for(j=0; j<M; ++j){
if(this->array[i][j] != 0 && this->findSet(i) != this->findSet(j)){
this->unionSet(i ,j);
}
}
}
int* p = new int[N];
std::uninitialized_fill_n(p, N, 0);//这里创建一个全部都是0的数组因为我们待会给的数据里面也都是1,0.
for(i=0; i<N; ++i){
for(j=0; j<tempCount; ++j){
if(this->findSet(i) == this->findSet(p[j])){ //p相当于是总集合内各个子集合的代表.
break;
}
}
if(j >= count){
p[count++] = i;
}
}
delete[] p;
p=nullptr;
return count;
}
template<unsigned int N, unsigned int M>
void SetData<N, M>::makeSet(const int& x)//创建一个单元集.
{
this->A[x] = x; //创建一个单元集:其意义是A这个数组中A[0], A[1]....分别代表一个数组,存储在A中的都是数组的代表其实也就是集合中的一个元素.
this->B[x] = 0; //B[0], B[1]....分别代表上面的A[0], A[1]中元素的个数.
}
template<unsigned int N, unsigned int M>
int SetData<N, M>::findSet(const int& x) //x其实是一个集合的代表. 压缩路径的查找方法.
{
if(x != this->A[x]){ //查找集合 x时候存在集合的代表A中.
this->A[x] = this->findSet(this->A[x]);
}
return this->A[x];
/*
//非递归方式压缩路径查找:
int a;
int b;
int c;
a=x; //令a等于元素x;
while(a != this->A[x]){ //查找集合a(即x)的父结点.
a = this->A[x]; //用a记录集合x的父结点.
}
b = x; //令b等于刚刚传递进来的集合x;
while(a != b){ //当a(即x)不等于x的根结点的时候.
c = this->A[a]; //令c等于根结点.
this->A[a] = r; //令x的根结点等于刚刚找到的根结点.
a = c;
}
return c;
*/
}
template<unsigned int N, unsigned int M>
void SetData<N, M>::unionSet(const int& x, const int& y)
{
this->link(this->findSet(x), this->findSet(y));
}
template<unsigned int N, unsigned int M>
void SetData<N, M>::link(const int& x, const int& y) //合并的时候假定集合x和集合y是不相交的.
{
if(this->B[x] > this->B[y]){ //当集合x内元素的个数大于集合y中元素个数的时候把集合 x接到结合y后面.
this->A[y] = x;
}else{
this->A[x] = y;
if(this->B[x] == this->B[y]){
this->B[y]++;
}
}
}
int main()
{
int myArray[10][10]={
{0, 1, 1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 1, 1, 0, 0, 0, 0, 0, 0},
{1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1, 1, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
{0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
SetData<10, 10> myData(myArray);
std::cout<<myData.connectedComponent()<<std::endl;
return 0;
}