您的位置:首页 > 其它

深度优先搜索检测有向图有无环路算法

2015-01-30 20:48 441 查看
给定有向图 G = (V, E),需要判断该图中是否存在环路(Cycle)。例如,下面的图 G 中包含 4 个顶点和 6 条边。



实际上,上图中存在 3 个环路:0->2->0, 0->1->2->0, 3->3。

深度优先搜索(DFS:Depth-First Search)可以用于检测图中是否存在环。DFS 会对一个连通的图构造一颗树,如果在构造树的过程中出现反向边(Back Edge),则认为图中存在环路。



对于非连通图,可以对图中的不同部分分别进行 DFS 构造树结构,对于每棵树分别检测反向边的存在。

在 DFS 对图进行遍历时,将遍历过的顶点放入递归栈中,如果新遍历的顶点已经存在于递归栈中,则说明存在一个反向边,即存在一个环。

using System;
using System.Collections.Generic;
using System.Linq;

namespace GraphAlgorithmTesting
{
class Program
{
static void Main(string[] args)
{
Graph g = new Graph(6);
g.AddEdge(0, 1, 16);
g.AddEdge(0, 2, 13);
g.AddEdge(1, 2, 10);
g.AddEdge(1, 3, 12);
g.AddEdge(2, 1, 4);
g.AddEdge(2, 4, 14);
//g.AddEdge(3, 2, 9);
g.AddEdge(3, 5, 20);
//g.AddEdge(4, 3, 7);
//g.AddEdge(4, 5, 4);

Console.WriteLine();
Console.WriteLine("Graph Vertex Count : {0}", g.VertexCount);
Console.WriteLine("Graph Edge Count : {0}", g.EdgeCount);
Console.WriteLine();

Console.WriteLine("Is there cycle in graph: {0}", g.HasCycle());

Console.ReadKey();
}

class Edge
{
public Edge(int begin, int end, int weight)
{
this.Begin = begin;
this.End = end;
this.Weight = weight;
}

public int Begin { get; private set; }
public int End { get; private set; }
public int Weight { get; private set; }

public override string ToString()
{
return string.Format(
"Begin[{0}], End[{1}], Weight[{2}]",
Begin, End, Weight);
}
}

class Graph
{
private Dictionary<int, List<Edge>> _adjacentEdges
= new Dictionary<int, List<Edge>>();

public Graph(int vertexCount)
{
this.VertexCount = vertexCount;
}

public int VertexCount { get; private set; }

public IEnumerable<int> Vertices { get { return _adjacentEdges.Keys; } }

public IEnumerable<Edge> Edges
{
get { return _adjacentEdges.Values.SelectMany(e => e); }
}

public int EdgeCount { get { return this.Edges.Count(); } }

public void AddEdge(int begin, int end, int weight)
{
if (!_adjacentEdges.ContainsKey(begin))
{
var edges = new List<Edge>();
_adjacentEdges.Add(begin, edges);
}

_adjacentEdges[begin].Add(new Edge(begin, end, weight));
}

public bool HasCycle()
{
// mark all the vertices as not visited
// and not part of recursion stack
bool[] visited = new bool[VertexCount];
bool[] recursionStack = new bool[VertexCount];
for (int i = 0; i < VertexCount; i++)
{
visited[i] = false;
recursionStack[i] = false;
}

// call the recursive helper function to
// detect cycle in different DFS trees
for (int i = 0; i < VertexCount; i++)
if (CheckCyclic(i, visited, recursionStack))
return true;

return false;
}

private bool CheckCyclic(int v, bool[] visited, bool[] recursionStack)
{
if (!visited[v])
{
// mark the current node as visited
// and part of recursion stack
visited[v] = true;
recursionStack[v] = true;

// recur for all the vertices adjacent to this vertex
if (_adjacentEdges.ContainsKey(v))
{
foreach (var edge in _adjacentEdges[v])
{
if (!visited[edge.End]
&& CheckCyclic(edge.End, visited, recursionStack))
return true;
else if (recursionStack[edge.End])
return true;
}
}
}

// remove the vertex from recursion stack
recursionStack[v] = false;

return false;
}
}
}
}


本篇文章《DFS 检测有向图有无环算法》由 Dennis Gao 发表自博客园,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫转载行为均为耍流氓。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: