資料結構實現 9.1:並查集_陣列結構實現(C++版)
阿新 • • 發佈:2018-11-27
資料結構實現 9.1:並查集_陣列結構實現(C++版)
1. 概念及基本框架
並查集 是一種高階資料結構,主要用於表示元素間的關係,即元素是否歸屬於同一個集合。
如上圖,不同的顏色表示不同的集合,裡面的數字表示元素儲存的資料。下面給出並查集的基本介面。
class UnionFind{
public:
virtual int size() = 0;
virtual bool isEmpty() = 0;
//是否連線
virtual bool isConnected(int p, int q) = 0;
//聯合元素
virtual void unionElements(int p, int q) = 0;
};
我們使用陣列來實現並查集,這裡我們忽略每個元素的資料,用每個元素的階表示元素本身,用陣列中存的數字表示元素所屬集合。那麼並查集的實現過程如下:
1.將每個元素初始化成自身,在下面的建構函式中實現。
2.聯合,將需要聯合的元素中儲存的數字統一為一個。
3.查詢,只要陣列中儲存的數字是一樣的,那麼認為兩個元素屬於同一個集合。
class QuickFind : public UnionFind{
public:
QuickFind(int size){
m_data = new int[size];
for (int i = 0; i < size; ++i){
m_data[i] = i;
}
m_size = size;
}
...
private:
int *m_data;
int m_size;
};
m_data 用來表示陣列。
m_size 表示並查集大小。
接下來我們就對並查集的聯合、查詢以及一些其他基本操作用程式碼去實現。
2. 基本操作程式實現
2.1 聯合操作
class QuickFind : public UnionFind{
public:
...
//聯合元素
void unionElements(int p, int q){
if (p == q){
return;
}
for (int i = 0; i < m_size; ++i){
if (m_data[i] == m_data[q]){
m_data[i] = m_data[p];
}
}
}
...
};
聯合元素時,需要遍歷一遍陣列,然後把需要聯合的元素都聯合起來。
2.2 查詢操作
class QuickFind : public UnionFind{
public:
...
//是否連線
bool isConnected(int p, int q){
return find(p) == find(q);
}
...
private:
int find(int index){
if (index < 0 || index >= m_size){
cout << "訪問越界!" << endl;
throw 0;
}
return m_data[index];
}
...
};
用於查詢兩個元素是否被聯合在一起。
2.3 其他操作
線段樹還有一些其他的操作,包括 並查集大小 等的查詢操作。
class QuickFind : public UnionFind{
public:
...
int size(){
return m_size;
}
bool isEmpty(){
return m_size == 0;
}
void print(){
cout << "QuickFind: " << "Size = " << m_size << endl;
cout << '[';
for (int i = 0; i < m_size; ++i){
cout << m_data[i];
if (i != m_size - 1){
cout << ',';
}
}
cout << ']' << endl;
}
...
};
3. 演算法複雜度分析
3.1 聯合操作
函式 | 最壞複雜度 | 平均複雜度 |
---|---|---|
unionElements | O(n) | O(n/2) = O(n) |
因為要遍歷一次陣列,所以聯合操作的時間複雜度為 O(n) 。
3.2 查詢操作
函式 | 最壞複雜度 | 平均複雜度 |
---|---|---|
isConnected | O(1) | O(1) |
總體情況:
操作 | 時間複雜度 |
---|---|
並 | O(n) |
查 | O(1) |
4. 完整程式碼
程式完整程式碼(這裡使用了標頭檔案的形式來實現類)如下:
虛擬函式介面 程式碼如下:
#ifndef __UNIONFIND_H__
#define __UNIONFIND_H__
class UnionFind{
public:
virtual int size() = 0;
virtual bool isEmpty() = 0;
//是否連線
virtual bool isConnected(int p, int q) = 0;
//聯合元素
virtual void unionElements(int p, int q) = 0;
};
#endif
並查集 類程式碼:
#ifndef __QUICKFIND_H__
#define __QUICKFIND_H__
#include "UnionFind.h"
class QuickFind : public UnionFind{
public:
QuickFind(int size){
m_data = new int[size];
for (int i = 0; i < size; ++i){
m_data[i] = i;
}
m_size = size;
}
int size(){
return m_size;
}
bool isEmpty(){
return m_size == 0;
}
void print(){
cout << "QuickFind: " << "Size = " << m_size << endl;
cout << '[';
for (int i = 0; i < m_size; ++i){
cout << m_data[i];
if (i != m_size - 1){
cout << ',';
}
}
cout << ']' << endl;
}
//是否連線
bool isConnected(int p, int q){
return find(p) == find(q);
}
//聯合元素
void unionElements(int p, int q){
if (p == q){
return;
}
for (int i = 0; i < m_size; ++i){
if (m_data[i] == m_data[q]){
m_data[i] = m_data[p];
}
}
}
private:
int find(int index){
if (index < 0 || index >= m_size){
cout << "訪問越界!" << endl;
throw 0;
}
return m_data[index];
}
private:
int *m_data;
int m_size;
};
#endif