用於不相交集合的操做ios
一個不相交集合的數據結構維護了一個不相交動態集的集合 S={s1, s2, s3,....},其中的s1,s2,s3都是集合.咱們用一個表明來標識每一個集合,該表明爲該集合的某個成員.數組
makeSet():建議一個新的集合,它的成員都是s1, s2, s3中的表明.因爲s1, s2 s3...是不相交的集合所以它的成員是不會有重複的。數據結構
unionSet(x, y):將包含x, y的兩個集合(sx, sy)合併成一個新的集合,即這兩個集合的並集.this
findSet(x): 返回一個成員,這個元素爲包含x的集合的表明.spa
#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; }