用并查集判断一个无向图中是否存在环

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。

  • Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集合。
  • Union:将两个子集合并成同一个集合。

其实判断一个图是否存在环已经有相应的算法,此文用并查集来判断一个图是否有环。

我们可以用一个一维数组parent[] 来记录子集合。

看下面这个图:

0

|                   

|    

1——2

对每一条边的两个顶点加入集合,发现两个相同的顶点在一个子集合中,就说明存在环。

初始化:parent[n] 的每个元素都为-1,共有n个子集合,表示集合只有当前顶点一个元素

0    1     2

-1   -1   -1

然后逐个处理每条边。

边0-1:我们找到两个子集合 0 和1,因为他们在不同的子集合,现在需要合并他们(Union). 把其中一个子集合作为对方的父集合.

0    1   2     <----- 1 成为 0 的 父集合 (1 现在代表集合 {0, 1})

1    -1  -1

边0-2:1属于属于子集合1,2属于子集合2,因此合并他们。

0   1    2     <----- 2 作为 1的父集合 (2 现在代表集合 {0, 1, 2})

1   2   -1

 边0-2: 0是在子集和2和2也是在子集合2, 因为 0->1->2 // 1 是0 父集合 并且  2 是1的父集合 。因此,找到了环

// 用并查集判断是否存在环
002
#include <stdio.h>
003
#include <stdlib.h>
004
#include <string.h>
005
 
006
// 图中的边
007
struct Edge
008
{
009
    int src, dest;
010
};
011
 
012
// 图结构体
013
struct Graph
014
{
015
    // V-> 顶点个数, E-> 边的个数
016
    int V, E;
017
 
018
    // 每个图就是 边的集合
019
    struct Edge* edge;
020
};
021
 
022
// 创建一个图
023
struct Graph* createGraph(int V, int E)
024
{
025
    struct Graph* graph = (struct Graph*) malloc( sizeof(struct Graph) );
026
    graph->V = V;
027
    graph->E = E;
028
 
029
    graph->edge = (struct Edge*) malloc( graph->E * sizeof( struct Edge ) );
030
 
031
    return graph;
032
}
033
 
034
// 查找元素i 所在的集合( 根 )
035
int find(int parent[], int i)
036
{
037
    if (parent[i] == -1)
038
        return i;
039
    return find(parent, parent[i]);
040
}
041
 
042
// 合并两个集合
043
void Union(int parent[], int x, int y)
044
{
045
    int xset = find(parent, x);
046
    int yset = find(parent, y);
047
    parent[xset] = yset;
048
}
049
 
050
// 检测环
051
int isCycle( struct Graph* graph )
052
{
053
    int *parent = (int*) malloc( graph->V * sizeof(int) );
054
 
055
    // 初始化所有集合
056
    memset(parent, -1, sizeof(int) * graph->V);
057
 
058
    // 遍历所有边
059
    for(int i = 0; i < graph->E; ++i)
060
    {
061
        int x = find(parent, graph->edge[i].src);
062
        int y = find(parent, graph->edge[i].dest);
063
 
064
        if (x == y) //如果在一个集合,就找到了环
065
            return 1;
066
 
067
        Union(parent, x, y);
068
    }
069
    return 0;
070
}
071
 
072
// 测试
073
int main()
074
{
075
    /* 创建一些的图
076
         0
077
        |  
078
        |    
079
        1-----2 */
080
    struct Graph* graph = createGraph(3, 3);
081
 
082
    // 添加边 0-1
083
    graph->edge[0].src = 0;
084
    graph->edge[0].dest = 1;
085
 
086
    // 添加边 1-2
087
    graph->edge[1].src = 1;
088
    graph->edge[1].dest = 2;
089
 
090
    // 添加边 0-2
091
    graph->edge[2].src = 0;
092
    graph->edge[2].dest = 2;
093
 
094
    if (isCycle(graph))
095
        printf( "Graph contains cycle" );
096
    else
097
        printf( "Graph doesn't contain cycle" );
098
 
099
    return 0;
100
}
View Code
原文地址:https://www.cnblogs.com/acm-jing/p/4655513.html