-
Notifications
You must be signed in to change notification settings - Fork 396
Expand file tree
/
Copy pathDirectedGraph.cs
More file actions
139 lines (119 loc) · 3.14 KB
/
DirectedGraph.cs
File metadata and controls
139 lines (119 loc) · 3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
using System;
using System.Collections.Generic;
using System.Linq;
namespace ReClassNET.Util
{
public class DirectedGraph<T>
{
private readonly IDictionary<T, HashSet<T>> adjacencyList = new Dictionary<T, HashSet<T>>();
/// <summary>
/// Gets an enumeration of all vertices in the graph.
/// </summary>
public IEnumerable<T> Vertices => adjacencyList.Keys;
/// <summary>
/// Adds the vertex to the graph.
/// </summary>
/// <param name="vertex"></param>
/// <returns></returns>
public bool AddVertex(T vertex)
{
if (adjacencyList.ContainsKey(vertex))
{
return false;
}
adjacencyList.Add(vertex, new HashSet<T>());
return true;
}
/// <summary>
/// Adds the vertices to the graph.
/// </summary>
/// <param name="vertices"></param>
public void AddVertices(IEnumerable<T> vertices)
{
foreach (var vertex in vertices)
{
AddVertex(vertex);
}
}
/// <summary>
/// Tests if the graph contains the given vertex.
/// </summary>
/// <param name="vertex"></param>
/// <returns></returns>
public bool ContainsVertex(T vertex)
{
return adjacencyList.ContainsKey(vertex);
}
/// <summary>
/// Adds an edge between both vertices to the graph.
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
/// <returns>True if a new edge was added, false otherwise.</returns>
public bool AddEdge(T from, T to)
{
if (!ContainsVertex(to) || !adjacencyList.TryGetValue(from, out var edges))
{
throw new ArgumentException("Vertex does not exist in graph.");
}
return edges.Add(to);
}
/// <summary>
/// Tests if the graph contains an edge between both vertices.
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
/// <returns></returns>
public bool ContainsEdge(T from, T to)
{
if (!ContainsVertex(to) || !adjacencyList.TryGetValue(from, out var edges))
{
throw new ArgumentException("Vertex does not exist in graph.");
}
return edges.Contains(to);
}
/// <summary>
/// Gets all neighbours of the given vertex.
/// </summary>
/// <param name="vertex">The vertex to check.</param>
/// <returns>An enumeration of all neighbours of the given vertex.</returns>
public IEnumerable<T> GetNeighbours(T vertex)
{
if (!adjacencyList.TryGetValue(vertex, out var edges))
{
throw new ArgumentException("Vertex does not exist in graph.");
}
return edges;
}
/// <summary>
/// Tests with a depth first search if the graph contains a cycle.
/// </summary>
/// <returns>True if a cycle exists, false otherwise.</returns>
public bool ContainsCycle()
{
var visited = new HashSet<T>();
var recursionStack = new HashSet<T>();
bool IsCyclic(T source)
{
if (visited.Add(source))
{
recursionStack.Add(source);
foreach (var adjacent in GetNeighbours(source))
{
if (!visited.Contains(adjacent) && IsCyclic(adjacent))
{
return true;
}
if (recursionStack.Contains(adjacent))
{
return true;
}
}
}
recursionStack.Remove(source);
return false;
}
return adjacencyList.Keys.Any(IsCyclic);
}
}
}