摘要:本文簡要介紹了並查集的基本原理,並且給出了簡單易於理解的數組實現。本文給出的實現方法
使用數組而不是通用的樹結構,是為了方便對並查集的理解,其合並的時間複雜度是O(N),不適合高效
的應用。高效的並查集實現請參見博文《並查集的樹形實現》。
關鍵字:並查集,Union,Find,Set,UnionFind
並查集是一個通用的數據結構,經典的應用有最小生成樹的Kruskal算法。該結構可用於判斷元素所
在的集合以及合並不相交的集合。一般並查集有三個主要的方法:
一是初始化,UnionFindSet_Init(int n),用於初始化並查集。
二是查找一個元素所在的集合,UnionFindSet_Find(int x),查找元素X。
三是合並兩個元素所在的集合,UnionFindSet_Merge(int x, int y)。
本文給出的實現中使用一個數組UnionFindSet[N]保存所有可能出現的元素,UnionSetFind[i]表示元素
i所在的集合編號,同一集合中的元素集合編號相同且唯一。首先將所有元素視為孤立的集合,為每個元素
設置一個集合編號;當合並某兩個元素所在的集合A和B時,將一個集合中的所有元素的集合編號設置為另
一個集合的元素編號;當查找某個元素所在的集合編號是,返回UnionSetFind[i]即可。
以上思想的C++實現如下:
/*
*並查集的數組實現
*/
//實現方法一,數組
//INIT時間複雜度,O(N)
//FIND時間複雜度,O(1)
//Merge時間複雜度,O(N)
#include <iostream>
using namespace std;
#define N 1000
int UnionFindSet[N];
void uf_init(int n); //初始化並查集,每個點都是一個集合
int uf_find(int x); //在並查集中查找一個元素,返回集合編號
void uf_merge(int x, int y, int n); //合並兩個元素所在的集合
int main(int argc, char* *argv)
{
int n = 20;
uf_init(n);
uf_merge(1, 3, n);
uf_merge(2, 3, n);
uf_merge(4, 5, n);
uf_merge(10, 13, n);
uf_merge(4, 13, n);
if(uf_find(1) == uf_find(3))
{
cout<<"success1"<<endl;
}
if(uf_find(5) == uf_find(10))
{
cout<<"success2"<<endl;
}
if(uf_find(1) != uf_find(4))
{
cout<<"success3"<<endl;
}
system("pause");
return 0;
}
void uf_init(int n)
{
//時間複雜度O(N)
for(int i = 0; i < n; ++i)
UnionFindSet[i] = i;
}
int uf_find(int x) //ensure x>=0 && x < n
{
//時間複雜度O(1)
return UnionFindSet[x];
}
void uf_merge(int x, int y, int n)//ensure x,y>=0 && x,y < n
{
//時間複雜度O(N)
int set_id1 = UnionFindSet[x];
int set_id2 = UnionFindSet[y];
for(int i = 0; i < n; ++i)
if(UnionFindSet[i] == set_id1)
UnionFindSet[i] = set_id2;
}