zoukankan      html  css  js  c++  java
  • Union-Find 检测无向图有无环路算法

    不相交集合数据结构(Disjoint-set data structure)是一种用于跟踪集合被分割成多个不相交的子集合的数据结构,每个集合通过一个代表来标识,代表即集合中的某个成员。

    Union-Find 算法为该数据结构提供了两种非常有用的操作:

    • Find:判断子集中是否存在特定的元素。可以用于检测是否两个元素存在于相同的子集中。
    • Union:将两个不子集合并成新的子集合。

    Union-Find 算法的一个具体的应用就是在无向图(Undirected Graph)中检测是否存在环路(Cycle)。

    例如,下面这张无向图 G:

    0
    | 
    |   
    1-----2

    G 中包含 3 个顶点和 3 条边 {{0, 1}, {1, 2}, {2, 1}}。

    初始时,设 int[] parent = new int[VertexCount],默认每个顶点的子集中只有自己,设为 -1。

    0   1  2
    -1 -1 -1

    处理边 {0, 1},Find 顶点 0 和 1 的子集,发现它们在不同的子集中,则 Union 它们,此时 1 代表了子集 {0, 1}。

    0  1  2
    1 -1 -1

    处理边 {1, 2},Find 顶点 1 和 2 的子集,发现它们在不同的子集中,则 Union 它们,此时 2 代表了子集 {0, 1, 2}。

    0 1  2
    1 2 -1

    处理边 {2, 1},Find 顶点 2 和 1 的子集,发现它们在相同的子集中,则图存在环。

    Union-Find 算法简单实现如下,其时间复杂度为 O(n)。

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 
      5 namespace GraphAlgorithmTesting
      6 {
      7   class Program
      8   {
      9     static void Main(string[] args)
     10     {
     11       Graph g = new Graph(6);
     12       g.AddEdge(0, 1, 16);
     13       g.AddEdge(0, 2, 13);
     14       g.AddEdge(1, 2, 10);
     15       g.AddEdge(1, 3, 12);
     16       //g.AddEdge(2, 1, 4);
     17       g.AddEdge(2, 4, 14);
     18       //g.AddEdge(3, 2, 9);
     19       g.AddEdge(3, 5, 20);
     20       //g.AddEdge(4, 3, 7);
     21       //g.AddEdge(4, 5, 4);
     22 
     23       Console.WriteLine();
     24       Console.WriteLine("Graph Vertex Count : {0}", g.VertexCount);
     25       Console.WriteLine("Graph Edge Count : {0}", g.EdgeCount);
     26       Console.WriteLine();
     27 
     28       Console.WriteLine("Is there cycle in graph: {0}", g.HasCycle());
     29 
     30       Console.ReadKey();
     31     }
     32 
     33     class Edge
     34     {
     35       public Edge(int begin, int end, int weight)
     36       {
     37         this.Begin = begin;
     38         this.End = end;
     39         this.Weight = weight;
     40       }
     41 
     42       public int Begin { get; private set; }
     43       public int End { get; private set; }
     44       public int Weight { get; private set; }
     45 
     46       public override string ToString()
     47       {
     48         return string.Format(
     49           "Begin[{0}], End[{1}], Weight[{2}]",
     50           Begin, End, Weight);
     51       }
     52     }
     53 
     54     class Graph
     55     {
     56       private Dictionary<int, List<Edge>> _adjacentEdges
     57         = new Dictionary<int, List<Edge>>();
     58 
     59       public Graph(int vertexCount)
     60       {
     61         this.VertexCount = vertexCount;
     62       }
     63 
     64       public int VertexCount { get; private set; }
     65 
     66       public IEnumerable<int> Vertices { get { return _adjacentEdges.Keys; } }
     67 
     68       public IEnumerable<Edge> Edges
     69       {
     70         get { return _adjacentEdges.Values.SelectMany(e => e); }
     71       }
     72 
     73       public int EdgeCount { get { return this.Edges.Count(); } }
     74 
     75       public void AddEdge(int begin, int end, int weight)
     76       {
     77         if (!_adjacentEdges.ContainsKey(begin))
     78         {
     79           var edges = new List<Edge>();
     80           _adjacentEdges.Add(begin, edges);
     81         }
     82 
     83         _adjacentEdges[begin].Add(new Edge(begin, end, weight));
     84       }
     85 
     86       private int Find(int[] parent, int i)
     87       {
     88         if (parent[i] == -1)
     89           return i;
     90         return Find(parent, parent[i]);
     91       }
     92 
     93       private void Union(int[] parent, int x, int y)
     94       {
     95         int xset = Find(parent, x);
     96         int yset = Find(parent, y);
     97         parent[xset] = yset;
     98       }
     99 
    100       public bool HasCycle()
    101       {
    102         int[] parent = new int[VertexCount];
    103         for (int i = 0; i < parent.Length; i++)
    104         {
    105           parent[i] = -1;
    106         }
    107 
    108         // Iterate through all edges of graph, find subset of both
    109         // vertices of every edge, if both subsets are same, 
    110         // then there is cycle in graph.
    111         foreach (var edge in this.Edges)
    112         {
    113           int x = Find(parent, edge.Begin);
    114           int y = Find(parent, edge.End);
    115 
    116           if (x == y)
    117           {
    118             return true;
    119           }
    120 
    121           Union(parent, x, y);
    122         }
    123 
    124         return false;
    125       }
    126     }
    127   }
    128 }

    本篇文章《Union-Find 检测无向图有无环路算法》由 Dennis Gao 发表自博客园,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫转载行为均为耍流氓。

  • 相关阅读:
    [堆栈]Linux 中的各种栈:进程栈 线程栈 内核栈 中断栈
    [TI-DSP]sysbios的swi
    [库函数]动态库和静态库优缺点比较
    [S32K]GPIO使用
    [S32K]FreeRTOS使用
    [IC]浅谈嵌入式MCU软件开发之中断优先级与中断嵌套
    [S32K144]多通道ADC使用
    三天搭建博客,包括文章迁移
    网站优化的艺术与科学之实战
    网站优化的艺术与科学之工具和基础知识
  • 原文地址:https://www.cnblogs.com/gaochundong/p/union_find_detect_cycle_in_an_undirected_graph.html
Copyright © 2011-2022 走看看