不相交集類是將一些元素合並為不相交的各個集合。在同一個集合中的元素兩兩等價,不同集合中的元素不等價。
vector對元素x的一次find(x)操作通過返回包含x的樹的根而完成。 合並操作union(root1, root2),將一棵樹的父節點鏈接到另一棵樹的根節點合並兩棵樹。s;//存放每個元素的根節點或父節點
合並操作union(4,5),將一棵樹的父節點鏈接到另一棵樹的根節點合並兩棵樹。
合並操作union(6,7),將一棵樹的父節點鏈接到另一棵樹的根節點合並兩棵樹。
第二種改進方法:
按高度求並,它同樣保證所有的樹的深度最多為O(logN)。我們跟蹤每棵樹的高度而不是大小並執行合並使得淺的樹成為深的樹的子樹。只有兩棵深度相等的樹求並的時候樹的高度才增加(樹的深度加1)。
為了實現按高度求並,需要記住每棵樹的高度,可以讓每個根元素包含它的樹的高度的負值。只有合並的兩棵樹高度相等的時候才需要更新樹的高度(根元素的值減去1)。
按樹高度合並的步驟:
explicit DisjSets(int numElements);
~DisjSets(){}
int find(int x) const;//查找
void unionSets(int root1, int root2);//合並
void unionSetsBySize(int root1, int root2);//按樹大小合並
void unionSetsByHeight(int root1, int root2);//按樹高度合並
void print();//輸出各個不相交集合類中元素
/****************************************************************
* 函數名稱:find(int x) const
* 功能描述: 查找元素x處於集合的名字
* 參數列表: x是要查找的元素
* 返回結果:返回元素x的集合名字
*****************************************************************/
int DisjSets::find(int x) const
{
if(s[x] < 0)
return x;
else
return find(s[x]);
}
/****************************************************************
* 函數名稱:unionSets(int root1, int root2)
* 功能描述: 合並兩個集合
* 參數列表: root1表示集合1,root2表示集合2
* 返回結果:void
*****************************************************************/
void DisjSets::unionSets(int root1, int root2)
{
s[root2] = root1;
}
(3):按樹的大小合並unionSetsBySize(int root1, int root2),使得較小的樹成為較大樹的子樹
/****************************************************************
* 函數名稱:unionSetsBySize(int root1, int root2)
* 功能描述: 按集合大小合並兩個集合,使得較小的樹成為較大樹的子樹
* 參數列表: root1表示集合1,root2表示集合2
* 返回結果:void
*****************************************************************/
void DisjSets::unionSetsBySize(int root1, int root2)
{
if(s[root2] < s[root1]){//root2樹比較大
s[root2] += s[root1];//更新樹的大小
s[root1] = root2;//root1的父節點變為root2
}
else{
s[root1] += s[root2];
s[root2] = root1;
}
}
/****************************************************************
* 函數名稱:unionSetsByHeight(int root1, int root2)
* 功能描述: 按集合高度合並兩個集合,使較淺的樹成為較深的樹的子樹
* 參數列表: root1表示集合1,root2表示集合2
* 返回結果:void
*****************************************************************/
void DisjSets::unionSetsByHeight(int root1, int root2)
{
if(s[root2] < s[root1]){//root2樹比較高
s[root1] = root2;//直接合並, root1成為root2樹的子樹
}
else{//root1樹比較高,或相等。
//如果相等則更新樹的高度
if(s[root1] == s[root2])
s[root1]--;
s[root2] = root1;
}
}
//測試主函數
int main()
{
cout << "任意合並: " << endl;
DisjSets disjSets(8);
disjSets.unionSets(4, 5);
disjSets.unionSets(6, 7);
disjSets.unionSets(4, 6);
disjSets.print();
cout << "按大小合並: " << endl;
DisjSets disjSets2(8);
disjSets2.unionSetsBySize(4, 5);
disjSets2.unionSetsBySize(6, 7);
disjSets2.unionSetsBySize(4, 6);
disjSets2.unionSetsBySize(3, 4);
disjSets2.print();
cout << "按高度合並: " << endl;
DisjSets disjSets3(8);
disjSets3.unionSetsByHeight(4, 5);
disjSets3.unionSetsByHeight(6, 7);
disjSets3.unionSetsByHeight(4, 6);
disjSets3.unionSetsByHeight(3, 4);
disjSets3.print();
return 0;
}
/************************************************************************* > File Name: DisjointSets.cpp > Author: > Mail: > Created Time: 2016年04月25日 星期一 11時22分48秒 ************************************************************************/ #include#include using namespace std; /******************************************** * 類名稱:不相交集合類DisjSets ********************************************/ class DisjSets{ public: explicit DisjSets(int numElements); ~DisjSets(){} int find(int x) const;//查找 void unionSets(int root1, int root2);//合並 void unionSetsBySize(int root1, int root2);//按樹大小合並 void unionSetsByHeight(int root1, int root2);//按樹高度合並 void print();//輸出各個不相交集合類中元素 private: void print(int x); private: vector s;//存放每個元素的根節點或父節點 }; /**************************************************************** * 函數名稱:DisjSets(int numElements) * 功能描述: 構造函數,同時對每個元素進行集合初始化 * 參數列表: numElements是集合中元素的個數 * 返回結果:無 *****************************************************************/ DisjSets::DisjSets(int numElements):s(numElements) { for(unsigned i = 0; i < s.size(); ++i) s[i] = -1; } /**************************************************************** * 函數名稱:print(int x) * 功能描述: 打印元素x * 參數列表: x是元素的 * 返回結果:void *****************************************************************/ void DisjSets::print(int x) { cout << x << " "; for(unsigned i = 0; i < s.size(); ++i){ if(s[i] == x) print(i); } } /**************************************************************** * 函數名稱:print * 功能描述: 打印集合中的元素 * 參數列表: 無 * 返回結果:void *****************************************************************/ void DisjSets::print() { cout << "輸出不相交集合類(每行表示一個相交集合): " << endl; cout << "s: "; for(unsigned i = 0; i < s.size(); ++i) cout << s[i] << " "; cout << endl; for(unsigned i = 0; i < s.size(); ++i){ if(s[i] < 0){ print(i); cout << endl; } } } /**************************************************************** * 函數名稱:find(int x) const * 功能描述: 查找元素x處於集合的名字 * 參數列表: x是要查找的元素 * 返回結果:返回元素x的集合名字 *****************************************************************/ int DisjSets::find(int x) const { if(s[x] < 0) return x; else return find(s[x]); } /**************************************************************** * 函數名稱:unionSets(int root1, int root2) * 功能描述: 合並兩個集合 * 參數列表: root1表示集合1,root2表示集合2 * 返回結果:void *****************************************************************/ void DisjSets::unionSets(int root1, int root2) { s[root2] = root1; } /**************************************************************** * 函數名稱:unionSetsBySize(int root1, int root2) * 功能描述: 按集合大小合並兩個集合,使得較小的樹成為較大樹的子樹 * 參數列表: root1表示集合1,root2表示集合2 * 返回結果:void *****************************************************************/ void DisjSets::unionSetsBySize(int root1, int root2) { if(s[root2] < s[root1]){//root2樹比較大 s[root2] += s[root1];//更新樹的大小 s[root1] = root2;//root1的父節點變為root2 } else{ s[root1] += s[root2]; s[root2] = root1; } } /**************************************************************** * 函數名稱:unionSetsByHeight(int root1, int root2) * 功能描述: 按集合高度合並兩個集合,使較淺的樹成為較深的樹的子樹 * 參數列表: root1表示集合1,root2表示集合2 * 返回結果:void *****************************************************************/ void DisjSets::unionSetsByHeight(int root1, int root2) { if(s[root2] < s[root1]){//root2樹比較高 s[root1] = root2;//直接合並, root1成為root2樹的子樹 } else{//root1樹比較高,或相等。 //如果相等則更新樹的高度 if(s[root1] == s[root2]) s[root1]--; s[root2] = root1; } } //測試主函數 int main() { cout << "任意合並: " << endl; DisjSets disjSets(8); disjSets.unionSets(4, 5); disjSets.unionSets(6, 7); disjSets.unionSets(4, 6); disjSets.print(); cout << "按大小合並: " << endl; DisjSets disjSets2(8); disjSets2.unionSetsBySize(4, 5); disjSets2.unionSetsBySize(6, 7); disjSets2.unionSetsBySize(4, 6); disjSets2.unionSetsBySize(3, 4); disjSets2.print(); cout << "按高度合並: " << endl; DisjSets disjSets3(8); disjSets3.unionSetsByHeight(4, 5); disjSets3.unionSetsByHeight(6, 7); disjSets3.unionSetsByHeight(4, 6); disjSets3.unionSetsByHeight(3, 4); disjSets3.print(); return 0; }
任意合並: 輸出不相交集合類(每行表示一個相交集合): s: -1 -1 -1 -1 -1 4 4 6 0 1 2 3 4 5 6 7 按大小合並: 輸出不相交集合類(每行表示一個相交集合): s: -1 -1 -1 4 -5 4 4 6 0 1 2 4 3 5 6 7 按高度合並: 輸出不相交集合類(每行表示一個相交集合): s: -1 -1 -1 4 -3 4 4 6 0 1 2 4 3 5 6 7