並查集是一種樹型的數據結構,用於處理一些不相交集合(Disjoint Sets)的合併及查詢問題。常常在使用中以森林來表示。集就是讓每個元素構成一個單元素的集合,也就是按一定順序將屬於同一組的元素所在的集合合併。
- Find:確定元素屬於哪一個子集。它可以被用來確定兩個元素是否屬於同一子集合。
- Union:將兩個子集合併成同一個集合。
// 用並查集判斷是否存在環
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 圖中的邊
struct Edge
{
int src, dest;
};
// 圖結構體
struct Graph
{
// V-> 頂點個數, E-> 邊的個數
int V, E;
// 每個圖就是 邊的集合
struct Edge* edge;
};
// 創建一個圖
struct Graph* createGraph(int V, int E)
{
struct Graph* graph = (struct Graph*) malloc( sizeof(struct Graph) );
graph->V = V;
graph->E = E;
graph->edge = (struct Edge*) malloc( graph->E * sizeof( struct Edge ) );
return graph;
}
// 查找元素i 所在的集合( 根 )
int find(int parent[], int i)
{
if (parent[i] == -1)
return i;
return find(parent, parent[i]);
}
// 合併兩個集合
void Union(int parent[], int x, int y)
{
int xset = find(parent, x);
int yset = find(parent, y);
parent[xset] = yset;
}
// 檢測環
int isCycle( struct Graph* graph )
{
int *parent = (int*) malloc( graph->V * sizeof(int) );
// 初始化所有集合
memset(parent, -1, sizeof(int) * graph->V);
// 遍歷所有邊
for(int i = 0; i < graph->E; ++i)
{
int x = find(parent, graph->edge[i].src);
int y = find(parent, graph->edge[i].dest);
if (x == y) //如果在一個集合,就找到了環
return 1;
Union(parent, x, y);
}
return 0;
}
// 測試
int main()
{
/* 創建一些的圖
0
| \
| \
1-----2 */
struct Graph* graph = createGraph(3, 3);
// 添加邊 0-1
graph->edge[0].src = 0;
graph->edge[0].dest = 1;
// 添加邊 1-2
graph->edge[1].src = 1;
graph->edge[1].dest = 2;
// 添加邊 0-2
graph->edge[2].src = 0;
graph->edge[2].dest = 2;
if (isCycle(graph))
printf( "Graph contains cycle" );
else
printf( "Graph doesn't contain cycle" );
return 0;
}