-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathTopologicalGraph.cs
More file actions
96 lines (78 loc) · 2.94 KB
/
TopologicalGraph.cs
File metadata and controls
96 lines (78 loc) · 2.94 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
using System;
using System.Collections.Generic;
using System.Linq;
namespace CSharp.DS.Graph
{
/// <summary>
/// DAG (Directed Acyclic Graph) used to model topological sort problems
/// </summary>
/// <typeparam name="T"></typeparam>
public class TopologicalGraph<T>
{
public class Node
{
public T val;
// (x, y): x is a prerequisite to y => y depends to x (y is a dependency)
public LinkedList<Node> dependencies;
public int numPrerequisites;
public Node(T val)
{
this.val = val;
dependencies = new LinkedList<Node>();
}
}
// Constant time removal for first/last Vertex
public Dictionary<T, Node> Vertexes;
public TopologicalGraph(T[] nodes, T[][] prerequisites)
{
Vertexes = new Dictionary<T, Node>();
// Create the Topological graph
foreach (var node in nodes)
AddVertex(nodeKey: node, node);
foreach (var prerequisite in prerequisites)
AddDependency(prerequisite[1], prerequisite[0]);
}
public void AddVertex(T nodeKey, T nodeValue)
{
if (Vertexes.ContainsKey(nodeKey))
throw new ArgumentException(nameof(nodeKey));
Vertexes.Add(nodeKey, new Node(nodeValue));
}
public void AddDependency(T prerequisiteKey, T dependencyKey)
{
if (!Vertexes.ContainsKey(prerequisiteKey))
throw new ArgumentException(nameof(prerequisiteKey));
if (!Vertexes.ContainsKey(dependencyKey))
throw new ArgumentException(nameof(dependencyKey));
Vertexes[prerequisiteKey].dependencies.AddLast(Vertexes[dependencyKey]);
Vertexes[dependencyKey].numPrerequisites++;
}
public List<T> TopologicalSort()
{
var topologicalList = new List<T>();
// Get nodes with no prerequisites
var noPrereqQueue = new Queue<Node>(
Vertexes.Where(kv => kv.Value.numPrerequisites == 0).Select(kv => kv.Value));
while (noPrereqQueue.Any())
{
var noPrereq = noPrereqQueue.Dequeue();
topologicalList.Add(noPrereq.val);
while (noPrereq.dependencies.Any())
{
var dependency = noPrereq.dependencies.Last();
noPrereq.dependencies.RemoveLast();
dependency.numPrerequisites--;
if (dependency.numPrerequisites == 0)
{
noPrereqQueue.Enqueue(dependency);
}
}
}
if (Vertexes.Values.Any(v => v.numPrerequisites > 0))
{
return new List<T>(); // dependency cycle
}
return topologicalList;
}
}
}