| C++ 實習測試: 1042 Quiz#1 互斥集合 (Disjoint Sets) |
| 令集合 S 為整數 0 到 n-1 的集合,「互斥集合 (disjoint-sets)」資料結構 (或稱為「不相交集合」, 也稱為 union-find 資料結構, 或是 merge-find 資料結構) 的定義如下:
|
| 我們可以用 陣列 簡單地實作 「互斥集合」資料結構, 用樹狀架構來代表各個子集合, 例如 DS2 = {0, 1, 2, 5}, {3, 6, 7}, {4} 表示為下圖之三個樹狀架構
用樹根節點作為這個子集合的代表元素, 下圖的整數陣列中每一個元素 parent[i] 中紀錄的是節點 i 的父節點, 如果是根節點的話 parent[i] 記錄的是 i 自己, 例如 DS2 = {0, 1, 2, 5}, {3, 6, 7}, {4} 以下列整數陣列表示
注意: 用這種表示方法來表示子集合並不是唯一的,同一個子集合可以有不同的樹狀架構,不考慮效率的情況下這個實作可以滿足下列 main() 函式中的基本測試 |
| 下面是一個實作 互斥集合 (Disjoint Sets) 的 C 程式 |
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <iomanip>
using namespace std;
void makeSets(int nNodes, int parent[]);
int findSets(int i, int nNodes, const int parent[]);
void mergeTrees(int i, int j, int nNodes, int parent[]);
void unionSets(int i, int j, int nNodes, int parent[]);
int equalSets(int nNodes1, const int parent1[], int nNodes2, const int parent2[]);
void printSets(int nNodes, const int parent[]);
int main()
{
const int nNodes=8;
int parent[nNodes];
int i;
const int p1[8] = {0,1,2,3,4,5,6,7};
const int p2[8] = {0,0,2,3,4,5,6,7};
const int p3[8] = {0,0,3,3,4,5,6,7};
const int p4[8] = {0,0,3,3,4,4,6,7};
const int p5[8] = {0,0,3,3,5,5,5,7};
const int p6[8] = {0,0,3,3,6,4,6,6};
const int p7[8] = {0,0,3,4,6,4,6,6};
const int p8[8] = {7,0,3,4,6,4,6,6};
makeSets(nNodes, parent);
assert(equalSets(nNodes, parent, nNodes, p1));
unionSets(0, 1, nNodes, parent);
assert(equalSets(nNodes, parent, nNodes, p2));
unionSets(2, 3, nNodes, parent);
assert(equalSets(nNodes, parent, nNodes, p3));
unionSets(4, 5, nNodes, parent);
assert(equalSets(nNodes, parent, nNodes, p4));
unionSets(4, 6, nNodes, parent);
assert(equalSets(nNodes, parent, nNodes, p5));
unionSets(4, 7, nNodes, parent);
assert(equalSets(nNodes, parent, nNodes, p6));
unionSets(3, 7, nNodes, parent);
assert(equalSets(nNodes, parent, nNodes, p7));
unionSets(2, 1, nNodes, parent);
assert(equalSets(nNodes, parent, nNodes, p8));
printSets(nNodes, parent);
system("pause");
return 0;
}
void printSets(int nNodes, const int parent[])
{
int i, j;
int *printed = (int *) malloc(nNodes*sizeof(int));
for (i=0; i<nNodes; i++) printed[i] = 0;
for (i=0; i<nNodes; i++)
if (!printed[i])
{
if (i==0)
cout << "{";
else
cout << ", {";
cout << i;
for (j=i+1; j<nNodes; j++)
if (!printed[j] &&
findSets(i, nNodes, parent)==findSets(j, nNodes, parent))
{
cout << ", " << j;
printed[j] = 1;
}
cout << "}";
}
cout << endl;
free(printed);
}
void makeSets(int nNodes, int parent[])
{
int i;
for (i=0; i<nNodes; i++)
parent[i] = i;
}
int findSets(int i, int nNodes, const int parent[])
{
if ((i<0)||(i>=nNodes)) return -1;
if (i == parent[i]) return i;
return findSets(parent[i], nNodes, parent);
}
void mergeTrees(int i, int j, int nNodes, int parent[])
{
if ((i<0)||(i>=nNodes)) return;
if ((j<0)||(j>=nNodes)) return;
parent[i] = j;
}
void unionSets(int i, int j, int nNodes, int parent[])
{
if ((i<0)||(i>=nNodes)) return;
if ((j<0)||(j>=nNodes)) return;
mergeTrees(findSets(i, nNodes, parent),
findSets(j, nNodes, parent),
nNodes, parent);
}
int equalSets(int nNodes1, const int parent1[], int nNodes2, const int parent2[])
{
if (nNodes1 != nNodes2) return 0;
for (int i=0; i<nNodes1; i++)
{
if (findSets(findSets(i, nNodes1, parent1), nNodes1, parent2) !=
findSets(i, nNodes1, parent2))
return 0;
if (findSets(findSets(i, nNodes1, parent2), nNodes1, parent1) !=
findSets(i, nNodes1, parent1))
return 0;
}
return 1;
} |
|
下面是一個實作 互斥集合 (Disjoint Sets) 的 C++ 物件化程式 |
/* DisjointSets.h */
#pragma once
class DisjointSets
{
public:
DisjointSets(void);
virtual ~DisjointSets(void);
void makeSets(int nNodes, const int *parent=0);
int findSets(int i) const;
void unionSets(int i, int j);
int equalSets(const DisjointSets& rhs) const;
void print();
static void unitTest(void);
private:
void mergeTrees(int i, int j);
int m_nNodes;
int m_parent[100];
};
/* DisjointSets.cpp */
#include "DisjointSets.h"
#include <cassert>
#include <iostream>
using namespace std;
DisjointSets::DisjointSets(void)
{
}
DisjointSets::~DisjointSets(void)
{
}
void DisjointSets::makeSets(int nNodes, const int *parent)
{
int i;
m_nNodes = nNodes;
if (parent == 0)
for (i=0; i<nNodes; i++)
m_parent[i] = i;
else
for (i=0; i<nNodes; i++)
m_parent[i] = parent[i];
}
int DisjointSets::findSets(int i) const
{
if ((i<0)||(i>=m_nNodes)) return -1;
if (i == m_parent[i]) return i;
return findSets(m_parent[i]);
}
void DisjointSets::mergeTrees(int i, int j)
{
if ((i<0)||(i>=m_nNodes)) return;
if ((j<0)||(j>=m_nNodes)) return;
m_parent[i] = j;
}
void DisjointSets::unionSets(int i, int j)
{
if ((i<0)||(i>=m_nNodes)) return;
if ((j<0)||(j>=m_nNodes)) return;
mergeTrees(findSets(i), findSets(j));
}
int DisjointSets::equalSets(const DisjointSets& rhs) const
{
int i;
if (m_nNodes != rhs.m_nNodes) return 0;
for (i=0; i<m_nNodes; i++)
if ((rhs.findSets(findSets(i)) != rhs.findSets(i)) ||
(findSets(rhs.findSets(i)) != findSets(i)))
return 0;
return 1;
}
void DisjointSets::unitTest(void)
{
const int nNodes=8;
int i;
const int p1[8] = {0,1,2,3,4,5,6,7};
const int p2[8] = {0,0,2,3,4,5,6,7};
const int p3[8] = {0,0,3,3,4,5,6,7};
const int p4[8] = {0,0,3,3,4,4,6,7};
const int p5[8] = {0,0,3,3,5,5,5,7};
const int p6[8] = {0,0,3,3,6,4,6,6};
const int p7[8] = {0,0,3,4,6,4,6,6};
const int p8[8] = {7,0,3,4,6,4,6,6};
DisjointSets ds1, ds2;
ds1.makeSets(nNodes);
ds2.makeSets(nNodes, p1);
assert(ds1.equalSets(ds2));
ds1.unionSets(0, 1);
ds2.makeSets(nNodes, p2);
assert(ds1.equalSets(ds2));
ds1.unionSets(2, 3);
ds2.makeSets(nNodes, p3);
assert(ds1.equalSets(ds2));
ds1.unionSets(4, 5);
ds2.makeSets(nNodes, p4);
assert(ds1.equalSets(ds2));
ds1.unionSets(4, 6);
ds2.makeSets(nNodes, p5);
assert(ds1.equalSets(ds2));
ds1.unionSets(4, 7);
ds2.makeSets(nNodes, p6);
assert(ds1.equalSets(ds2));
ds1.unionSets(3, 7);
ds2.makeSets(nNodes, p7);
assert(ds1.equalSets(ds2));
ds1.unionSets(2, 1);
ds2.makeSets(nNodes, p8);
assert(ds1.equalSets(ds2));
ds1.print();
}
void DisjointSets::print()
{
int i, j, printed[100];
for (i=0; i<m_nNodes; i++) printed[i] = 0;
for (i=0; i<m_nNodes; i++)
if (!printed[i])
{
if (i==0)
cout << "{";
else
cout << ", {";
cout << i;
for (j=i+1; j<m_nNodes; j++)
if (!printed[j] && findSets(i)==findSets(j))
{
cout << ", " << j;
printed[j] = 1;
}
cout << "}";
}
cout << endl;
}
/* main.cpp */
#include "DisjointSets.h"
#include <cstdlib>
int main()
{
DisjointSets::unitTest();
system("pause");
return 0;
} |

|
回
C++ 物件導向程式設計課程
首頁
製作日期: 03/25/2016 by 丁培毅 (Pei-yih Ting) E-mail: pyting@mail.ntou.edu.tw TEL: 02 24622192x6615 海洋大學 電機資訊學院 資訊工程學系 Lagoon |