Created
July 20, 2017 05:06
-
-
Save maxint137/a5239dac302b89cfc343a4928db78d45 to your computer and use it in GitHub Desktop.
Tarjan's strongly connected components algorithm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Main() | |
{ | |
int N = 8; | |
var nodes = new List<Node>(N + 1); | |
foreach (var n in Enumerable.Range(0, N + 1)) | |
{ | |
nodes.Add(new Node($"n{n}", null)); | |
} | |
nodes[1].setNodes(new Node[] { nodes[2] }); | |
nodes[2].setNodes(new Node[] { nodes[3], nodes[5], nodes[6], nodes[7] }); | |
nodes[4].setNodes(new Node[] { nodes[7] }); | |
nodes[5].setNodes(new Node[] { nodes[1] }); | |
nodes[6].setNodes(new Node[] { nodes[2], nodes[7] }); | |
nodes[7].setNodes(new Node[] { nodes[3], nodes[4] }); | |
nodes[8].setNodes(new Node[] { nodes[4] }); | |
new Graph(nodes); | |
} | |
class Graph | |
{ | |
List<Node> nodes; | |
public Dictionary<Node, uint> order = new Dictionary<UserQuery.Node, uint>(); | |
public Dictionary<Node, uint> link = new Dictionary<UserQuery.Node, uint>(); | |
uint cur_order = 0; | |
Stack<Node> s = new Stack<UserQuery.Node>(); | |
public Graph(IEnumerable<Node> nodes) | |
{ | |
this.nodes = new List<Node>(nodes.Count()); | |
this.nodes.AddRange(nodes); | |
Tarjan(); | |
} | |
void Tarjan() | |
{ | |
foreach (var n in nodes) | |
{ | |
if (!order.Keys.Contains(n)) | |
{ | |
StrongConnect(n); | |
} | |
} | |
} | |
void StrongConnect(Node u) | |
{ | |
// next node takes next number | |
order[u] = ++cur_order; | |
// starts with a link to itself | |
link[u] = order[u]; | |
s.Push(u); | |
// go over the neighbors | |
foreach (var v in u.nodes) | |
{ | |
// is it a new discovered node? | |
if (!order.Keys.Contains(v)) | |
{ | |
StrongConnect(v); | |
link[u] = Math.Min(link[u], link[v]); | |
} | |
else | |
{ | |
// we saw this node before | |
// is it on the stack <=> | |
if (s.Any(_=>_ == v)) | |
{ | |
// then v is in current component | |
link[u] = Math.Min(link[u], order[v]); | |
} | |
} | |
} | |
// then consider if we want to keep the current node on the stack | |
if (link[u] == order[u]) | |
{ | |
// u is the root of a new component | |
var scc = new List<Node>(); | |
while (true) | |
{ | |
var v = s.Pop(); | |
scc.Add(v); | |
if (u == v) | |
{ | |
break; | |
} | |
} | |
scc.Select(_=>_.name).Dump("SCC"); | |
} | |
} | |
} | |
class Node | |
{ | |
public string name { get; set; } | |
public List<Node> nodes { get; set; } | |
public void setNodes(IEnumerable<Node> ns) | |
{ | |
nodes = new List<Node>(); | |
if (null == ns) | |
{ | |
return; | |
} | |
nodes.AddRange(ns); | |
} | |
public Node(string name, IEnumerable<Node> ns) | |
{ | |
this.name = name; | |
this.setNodes(ns); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment