Skip to content

Instantly share code, notes, and snippets.

@maxint137
Created July 20, 2017 05:06
Show Gist options
  • Save maxint137/a5239dac302b89cfc343a4928db78d45 to your computer and use it in GitHub Desktop.
Save maxint137/a5239dac302b89cfc343a4928db78d45 to your computer and use it in GitHub Desktop.
Tarjan's strongly connected components algorithm
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