Tarjan: Difference between revisions

49,204 bytes added ,  3 months ago
m
(→‎{{header|Python}}: don't use a list as the default argument)
m (→‎{{header|Wren}}: Minor tidy)
(39 intermediate revisions by 15 users not shown)
Line 2:
{{wikipedia|Graph}}
[[Category:Algorithm]]
 
<br>
 
Tarjan's algorithm is an algorithm in graph theory for finding the strongly connected components of a graph. It runs in linear time, matching the time bound for alternative methods including Kosaraju's algorithm and the path-based strong component algorithm. Tarjan's Algorithm is named for its discoverer, Robert Tarjan.
Tarjan's algorithm is an algorithm in graph theory for finding the strongly connected components of a graph.
<br>
 
It runs in linear time, matching the time bound for alternative methods including Kosaraju's algorithm and the path-based strong component algorithm.
 
Tarjan's Algorithm is named for its discoverer, Robert Tarjan.
 
 
;References:
* The article on [[wp:Tarjan's_strongly_connected_components_algorithm|Wikipedia]].
 
See also: [[Kosaraju]]
<br><br>
 
=={{header|11l}}==
{{trans|Python: As class}}
 
<syntaxhighlight lang="11l">T Graph
String name
[Char = [Char]] graph
Int _order
[Char = Int] disc
[Char = Int] low
[Char] stack
[[Char]] scc
 
F (name, connections)
.name = name
 
DefaultDict[Char, [Char]] g
L(n) connections
V (n1, n2) = (n[0], n[1])
I n1 != n2
g[n1].append(n2)
E
g[n1]
g[n2]
 
.graph = Dict(move(g))
.tarjan_algo()
 
F _visitor(this) -> N
Recursive function that finds SCC's
using DFS traversal of vertices.
 
Arguments:
this --> Vertex to be visited in this call.
disc{} --> Discovery order of visited vertices.
low{} --> Connected vertex of earliest discovery order
stack --> Ancestor node stack during DFS.
.disc[this] = .low[this] = ._order
._order++
.stack.append(this)
 
L(neighbr) .graph[this]
I neighbr !C .disc
._visitor(neighbr)
.low[this] = min(.low[this], .low[neighbr])
 
E I neighbr C .stack
.low[this] = min(.low[this], .disc[neighbr])
 
I .low[this] == .disc[this]
[Char] new
L
V top = .stack.pop()
new.append(top)
I top == this
L.break
.scc.append(new)
 
F tarjan_algo()
Recursive function that finds strongly connected components
using the Tarjan Algorithm and function _visitor() to visit nodes.
._order = 0
 
L(vertex) sorted(.graph.keys())
I vertex !C .disc
._visitor(vertex)
 
L(n, m) [(‘Tx1’, ‘10 02 21 03 34’.split(‘ ’)),
(‘Tx2’, ‘01 12 23’.split(‘ ’)),
(‘Tx3’, ‘01 12 20 13 14 16 35 45’.split(‘ ’)),
(‘Tx4’, ‘01 03 12 14 20 26 32 45 46 56 57 58 59 64 79 89 98 AA’.split(‘ ’)),
(‘Tx5’, ‘01 12 23 24 30 42’.split(‘ ’))
]
print("\n\nGraph('#.', #.):\n".format(n, m))
V g = Graph(n, m)
print(‘ : ’sorted(g.disc.keys()).map(v -> String(v)).join(‘ ’))
print(‘ DISC of ’(g.name‘:’)‘ ’sorted(g.disc.items()).map((_, v) -> v))
print(‘ LOW of ’(g.name‘:’)‘ ’sorted(g.low.items()).map((_, v) -> v))
V scc = (I !g.scc.empty {String(g.scc).replace(‘'’, ‘’).replace(‘,’, ‘’)[1 .< (len)-1]} E ‘’)
print("\n SCC's of "(g.name‘:’)‘ ’scc)</syntaxhighlight>
 
{{out}}
<pre>
 
 
Graph('Tx1', [10, 02, 21, 03, 34]):
 
: 0 1 2 3 4
DISC of Tx1: [0, 2, 1, 3, 4]
LOW of Tx1: [0, 0, 0, 3, 4]
 
SCC's of Tx1: [4] [3] [1 2 0]
 
 
Graph('Tx2', [01, 12, 23]):
 
: 0 1 2 3
DISC of Tx2: [0, 1, 2, 3]
LOW of Tx2: [0, 1, 2, 3]
 
SCC's of Tx2: [3] [2] [1] [0]
 
 
Graph('Tx3', [01, 12, 20, 13, 14, 16, 35, 45]):
 
: 0 1 2 3 4 5 6
DISC of Tx3: [0, 1, 2, 3, 5, 4, 6]
LOW of Tx3: [0, 0, 0, 3, 5, 4, 6]
 
SCC's of Tx3: [5] [3] [4] [6] [2 1 0]
 
 
Graph('Tx4', [01, 03, 12, 14, 20, 26, 32, 45, 46, 56, 57, 58, 59, 64, 79, 89, 98, AA]):
 
: 0 1 2 3 4 5 6 7 8 9 A
DISC of Tx4: [0, 1, 2, 9, 4, 5, 3, 6, 8, 7, 10]
LOW of Tx4: [0, 0, 0, 2, 3, 3, 3, 6, 7, 7, 10]
 
SCC's of Tx4: [8 9] [7] [5 4 6] [3 2 1 0] [A]
 
 
Graph('Tx5', [01, 12, 23, 24, 30, 42]):
 
: 0 1 2 3 4
DISC of Tx5: [0, 1, 2, 3, 4]
LOW of Tx5: [0, 0, 0, 0, 2]
 
SCC's of Tx5: [4 3 2 1 0]
</pre>
 
=={{header|C|C}}==
<syntaxhighlight lang="c">#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
 
#ifndef min
#define min(x, y) ((x)<(y) ? (x) : (y))
#endif
 
struct edge {
void *from;
void *to;
};
 
struct components {
int nnodes;
void **nodes;
struct components *next;
};
 
struct node {
int index;
int lowlink;
bool onStack;
void *data;
};
 
struct tjstate {
int index;
int sp;
int nedges;
struct edge *edges;
struct node **stack;
struct components *head;
struct components *tail;
};
 
static int nodecmp(const void *l, const void *r)
{
return (ptrdiff_t)l -(ptrdiff_t)((struct node *)r)->data;
}
 
static int strongconnect(struct node *v, struct tjstate *tj)
{
struct node *w;
 
/* Set the depth index for v to the smallest unused index */
v->index = tj->index;
v->lowlink = tj->index;
tj->index++;
tj->stack[tj->sp] = v;
tj->sp++;
v->onStack = true;
 
for (int i = 0; i<tj->nedges; i++) {
/* Only consider nodes reachable from v */
if (tj->edges[i].from != v) {
continue;
}
w = tj->edges[i].to;
/* Successor w has not yet been visited; recurse on it */
if (w->index == -1) {
int r = strongconnect(w, tj);
if (r != 0)
return r;
v->lowlink = min(v->lowlink, w->lowlink);
/* Successor w is in stack S and hence in the current SCC */
} else if (w->onStack) {
v->lowlink = min(v->lowlink, w->index);
}
}
 
/* If v is a root node, pop the stack and generate an SCC */
if (v->lowlink == v->index) {
struct components *ng = malloc(sizeof(struct components));
if (ng == NULL) {
return 2;
}
if (tj->tail == NULL) {
tj->head = ng;
} else {
tj->tail->next = ng;
}
tj->tail = ng;
ng->next = NULL;
ng->nnodes = 0;
do {
tj->sp--;
w = tj->stack[tj->sp];
w->onStack = false;
ng->nnodes++;
} while (w != v);
ng->nodes = malloc(ng->nnodes*sizeof(void *));
if (ng == NULL) {
return 2;
}
for (int i = 0; i<ng->nnodes; i++) {
ng->nodes[i] = tj->stack[tj->sp+i]->data;
}
}
return 0;
}
 
static int ptrcmp(const void *l, const void *r)
{
return (ptrdiff_t)((struct node *)l)->data
- (ptrdiff_t)((struct node *)r)->data;
}
 
/**
* Calculate the strongly connected components using Tarjan's algorithm:
* en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
*
* Returns NULL when there are invalid edges and sets the error to:
* 1 if there was a malformed edge
* 2 if malloc failed
*
* @param number of nodes
* @param data of the nodes (assumed to be unique)
* @param number of edges
* @param data of edges
* @param pointer to error code
*/
struct components *tarjans(
int nnodes, void *nodedata[],
int nedges, struct edge *edgedata[],
int *error)
{
struct node nodes[nnodes];
struct edge edges[nedges];
struct node *stack[nnodes];
struct node *from, *to;
struct tjstate tj = {0, 0, nedges, edges, stack, NULL, .tail=NULL};
 
// Populate the nodes
for (int i = 0; i<nnodes; i++) {
nodes[i] = (struct node){-1, -1, false, nodedata[i]};
}
qsort(nodes, nnodes, sizeof(struct node), ptrcmp);
 
// Populate the edges
for (int i = 0; i<nedges; i++) {
from = bsearch(edgedata[i]->from, nodes, nnodes,
sizeof(struct node), nodecmp);
if (from == NULL) {
*error = 1;
return NULL;
}
to = bsearch(edgedata[i]->to, nodes, nnodes,
sizeof(struct node), nodecmp);
if (to == NULL) {
*error = 1;
return NULL;
}
edges[i] = (struct edge){.from=from, .to=to};
}
 
//Tarjan's
for (int i = 0; i < nnodes; i++) {
if (nodes[i].index == -1) {
*error = strongconnect(&nodes[i], &tj);
if (*error != 0)
return NULL;
}
}
return tj.head;
}
</syntaxhighlight>
 
=={{header|C sharp|C#}}==
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
 
class Node
{
public int LowLink { get; set; }
public int Index { get; set; }
public int N { get; }
 
public Node(int n)
{
{
N = n;
Index = -1;
LowLink = 0;
}
}
}
 
class Graph
{
public HashSet<Node> V { get; }
public Dictionary<Node, HashSet<Node>> Adj { get; }
 
/// <summary>
/// Tarjan's strongly connected components algorithm
/// </summary>
public void Tarjan()
{
{
var index = 0; // number of nodes
var S = new Stack<Node>();
 
Action<Node> StrongConnect = null;
StrongConnect = (v) =>
{
{
// Set the depth index for v to the smallest unused index
v.Index = index;
v.LowLink = index;
 
index++;
S.Push(v);
 
// Consider successors of v
foreach (var w in Adj[v])
if (w.Index < 0)
{
{
// Successor w has not yet been visited; recurse on it
StrongConnect(w);
v.LowLink = Math.Min(v.LowLink, w.LowLink);
}
}
else if (S.Contains(w))
// Successor w is in stack S and hence in the current SCC
v.LowLink = Math.Min(v.LowLink, w.Index);
 
// If v is a root node, pop the stack and generate an SCC
if (v.LowLink == v.Index)
{
{
Console.Write("SCC: ");
 
Node w;
do
do
{
{
w = S.Pop();
Console.Write(w.N + " ");
} while (w != v);
 
Console.WriteLine();
}
}
};
};
 
foreach (var v in V)
if (v.Index < 0)
StrongConnect(v);
}
}
}</langsyntaxhighlight>
 
=={{header|C++}}==
<syntaxhighlight lang="cpp">//
// C++ implementation of Tarjan's strongly connected components algorithm
// See https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
//
#include <algorithm>
#include <iostream>
#include <list>
#include <string>
#include <vector>
 
struct noncopyable {
noncopyable() {}
noncopyable(const noncopyable&) = delete;
noncopyable& operator=(const noncopyable&) = delete;
};
 
template <typename T>
class tarjan;
 
template <typename T>
class vertex : private noncopyable {
public:
explicit vertex(const T& t) : data_(t) {}
void add_neighbour(vertex* v) {
neighbours_.push_back(v);
}
void add_neighbours(const std::initializer_list<vertex*>& vs) {
neighbours_.insert(neighbours_.end(), vs);
}
const T& get_data() {
return data_;
}
private:
friend tarjan<T>;
T data_;
int index_ = -1;
int lowlink_ = -1;
bool on_stack_ = false;
std::vector<vertex*> neighbours_;
};
 
template <typename T>
class graph : private noncopyable {
public:
vertex<T>* add_vertex(const T& t) {
vertexes_.emplace_back(t);
return &vertexes_.back();
}
private:
friend tarjan<T>;
std::list<vertex<T>> vertexes_;
};
 
template <typename T>
class tarjan : private noncopyable {
public:
using component = std::vector<vertex<T>*>;
std::list<component> run(graph<T>& graph) {
index_ = 0;
stack_.clear();
strongly_connected_.clear();
for (auto& v : graph.vertexes_) {
if (v.index_ == -1)
strongconnect(&v);
}
return strongly_connected_;
}
private:
void strongconnect(vertex<T>* v) {
v->index_ = index_;
v->lowlink_ = index_;
++index_;
stack_.push_back(v);
v->on_stack_ = true;
for (auto w : v->neighbours_) {
if (w->index_ == -1) {
strongconnect(w);
v->lowlink_ = std::min(v->lowlink_, w->lowlink_);
}
else if (w->on_stack_) {
v->lowlink_ = std::min(v->lowlink_, w->index_);
}
}
if (v->lowlink_ == v->index_) {
strongly_connected_.push_back(component());
component& c = strongly_connected_.back();
for (;;) {
auto w = stack_.back();
stack_.pop_back();
w->on_stack_ = false;
c.push_back(w);
if (w == v)
break;
}
}
}
int index_ = 0;
std::list<vertex<T>*> stack_;
std::list<component> strongly_connected_;
};
 
template <typename T>
void print_vector(const std::vector<vertex<T>*>& vec) {
if (!vec.empty()) {
auto i = vec.begin();
std::cout << (*i)->get_data();
for (++i; i != vec.end(); ++i)
std::cout << ' ' << (*i)->get_data();
}
std::cout << '\n';
}
 
int main() {
graph<std::string> g;
auto andy = g.add_vertex("Andy");
auto bart = g.add_vertex("Bart");
auto carl = g.add_vertex("Carl");
auto dave = g.add_vertex("Dave");
auto earl = g.add_vertex("Earl");
auto fred = g.add_vertex("Fred");
auto gary = g.add_vertex("Gary");
auto hank = g.add_vertex("Hank");
 
andy->add_neighbour(bart);
bart->add_neighbour(carl);
carl->add_neighbour(andy);
dave->add_neighbours({bart, carl, earl});
earl->add_neighbours({dave, fred});
fred->add_neighbours({carl, gary});
gary->add_neighbour(fred);
hank->add_neighbours({earl, gary, hank});
 
tarjan<std::string> t;
for (auto&& s : t.run(g))
print_vector(s);
return 0;
}</syntaxhighlight>
 
{{out}}
<pre>
Carl Bart Andy
Gary Fred
Earl Dave
Hank
</pre>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 158 ⟶ 616:
}
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 167 ⟶ 625:
</pre>
 
=={{header|J}}==
 
Brute force implementation from wikipedia pseudocode:
 
<syntaxhighlight lang=J>tarjan=: {{
coerase ([ cocurrent) cocreate'' NB. following =: declarations are temporary, expiring when we finish
graph=: y NB. connection matrix of a directed graph
result=: stack=: i.index=: 0
undef=: #graph
lolinks=: indices=: undef"_1 graph
onstack=: 0"_1 graph
strongconnect=: {{
indices=: index y} indices
lolinks=: index y} lolinks
onstack=: 1 y} onstack
stack=: stack,y
index=: index+1
for_w. y{::graph do.
if. undef = w{indices do.
strongconnect w
lolinks=: (<./lolinks{~y,w) y} lolinks
elseif. w{onstack do.
lolinks=: (<./lolinks{~y,w) y} lolinks
end.
end.
if. lolinks =&(y&{) indices do.
loc=. stack i. y
component=. loc }. stack
onstack=: 0 component} onstack
result=: result,<component
stack=: loc {. stack
end.
}}
for_Y. i.#graph do.
if. undef=Y{indices do.
strongconnect Y
end.
end.
result
}}</syntaxhighlight>
 
Example use, with graph from wikipedia animated example:
 
<syntaxhighlight lang=J> tarjan 1;2;0;1 2 4;3 5;2 6;5;4 6 7
┌─────┬───┬───┬─┐
│0 1 2│5 6│3 4│7│
└─────┴───┴───┴─┘</syntaxhighlight>
 
=={{header|Java}}==
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
 
public final class TarjanSCC {
public static void main(String[] aArgs) {
Graph graph = new Graph(8);
graph.addDirectedEdge(0, 1);
graph.addDirectedEdge(1, 2); graph.addDirectedEdge(1, 7);
graph.addDirectedEdge(2, 3); graph.addDirectedEdge(2, 6);
graph.addDirectedEdge(3, 4);
graph.addDirectedEdge(4, 2); graph.addDirectedEdge(4, 5);
graph.addDirectedEdge(6, 3); graph.addDirectedEdge(6, 5);
graph.addDirectedEdge(7, 0); graph.addDirectedEdge(7, 6);
System.out.println("The strongly connected components are: ");
for ( Set<Integer> component : graph.getSCC() ) {
System.out.println(component);
}
}
}
 
final class Graph {
 
public Graph(int aSize) {
adjacencyLists = new ArrayList<Set<Integer>>(aSize);
for ( int i = 0; i < aSize; i++ ) {
vertices.add(i);
adjacencyLists.add( new HashSet<Integer>() );
}
}
public void addDirectedEdge(int aFrom, int aTo) {
adjacencyLists.get(aFrom).add(aTo);
}
public List<Set<Integer>> getSCC() {
for ( int vertex : vertices ) {
if ( ! numbers.keySet().contains(vertex) ) {
stronglyConnect(vertex);
}
}
return stronglyConnectedComponents;
}
private void stronglyConnect(int aVertex) {
numbers.put(aVertex, index);
lowlinks.put(aVertex, index);
index += 1;
stack.push(aVertex);
for ( int adjacent : adjacencyLists.get(aVertex) ) {
if ( ! numbers.keySet().contains(adjacent) ) {
stronglyConnect(adjacent);
lowlinks.put(aVertex, Math.min(lowlinks.get(aVertex), lowlinks.get(adjacent)));
} else if ( stack.contains(adjacent) ) {
lowlinks.put(aVertex, Math.min(lowlinks.get(aVertex), numbers.get(adjacent)));
}
}
if ( lowlinks.get(aVertex) == numbers.get(aVertex) ) {
Set<Integer> stonglyConnectedComponent = new HashSet<Integer>();
int top;
do {
top = stack.pop();
stonglyConnectedComponent.add(top);
} while ( top != aVertex );
stronglyConnectedComponents.add(stonglyConnectedComponent);
}
}
private List<Set<Integer>> adjacencyLists;
private List<Integer> vertices = new ArrayList<Integer>();
private int index = 0;
private Stack<Integer> stack = new Stack<Integer>();
private Map<Integer, Integer> numbers = new HashMap<Integer, Integer>();
private Map<Integer, Integer> lowlinks = new HashMap<Integer, Integer>();
private List<Set<Integer>> stronglyConnectedComponents = new ArrayList<Set<Integer>>();
 
}
</syntaxhighlight>
{{ out }}
<pre>
The strongly connected components are:
[5]
[2, 3, 4, 6]
[0, 1, 7]
</pre>
 
=={{header|jq}}==
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
 
In this adaptation of the [[#Kotlin]]/[[#Wren]] implementations:
* a Node is represented by JSON object with .n being its id;
* a DirectedGraph is represented by a JSON object {vs, es} where vs is an array of Nodes and es is an array of integer ids;
* a Stack is reprsented by an array, with .[-1] as the active point;
* the output of `tarjan` is an array each item of which is an array of Node ids.
<br>
<syntaxhighlight lang="jq"># Input: an integer
def Node:
{ n: .,
index: -1, # -1 signifies undefined
lowLink: -1,
onStack: false
} ;
 
# Input: a DirectedGraph
# Output: a stream of Node ids
def successors($vn): .es[$vn][];
 
# Input: a DirectedGraph
# Output: an array of integer arrays
def tarjan:
. + { sccs: [], # strongly connected components
index: 0,
s: [] # Stack
}
# input: {es, vs, sccs, index, s}
| def strongConnect($vn):
# Set the depth index for v to the smallest unused index
.vs[$vn].index = .index
| .vs[$vn].lowLink = .index
| .index += 1
| .s += [ $vn ]
| .vs[$vn].onStack = true
# consider successors of v
| reduce successors($vn) as $wn (.;
if .vs[$wn].index < 0
then
# Successor w has not yet been visited; recurse on it
strongConnect($wn)
| .vs[$vn].lowLink = ([.vs[$vn].lowLink, .vs[$wn].lowLink] | min )
elif .vs[$wn].onStack
then
# Successor w is in stack s and hence in the current SCC
.vs[$vn].lowLink = ([.vs[$vn].lowLink, .vs[$wn].index] | min )
else .
end
)
# If v is a root node, pop the stack and generate an SCC
| if .vs[$vn] | (.lowLink == .index)
then .scc = []
| .stop = false
| until(.stop;
.s[-1] as $wn
| .s |= .[:-1] # pop
| .vs[$wn].onStack = false
| .scc += [$wn]
| if $wn == $vn then .stop = true else . end )
| .sccs += [.scc]
else .
end
;
reduce .vs[].n as $vn (.;
if .vs[$vn].index < 0
then strongConnect($vn)
else . end
)
| .sccs
;
 
# Vertices
def vs: [range(0;8) | Node ];
 
# Edges
def es:
[ [1],
[2],
[0],
[1, 2, 4],
[5, 3],
[2, 6],
[5],
[4, 7, 6]
]
;
 
{ vs: vs, es: es }
| tarjan</syntaxhighlight>
{{out}}
<pre>
[[2,1,0],[6,5],[4,3],[7]]
</pre>
 
=={{header|Julia}}==
LightGraphs uses Tarjan's algorithm by default. The package can also use Kosaraju's algorithm with the function strongly_connected_components_kosaraju().
<langsyntaxhighlight lang="julia">using LightGraphs
 
edge_list=[(1,2),(3,1),(6,3),(6,7),(7,6),(2,3),(4,2),(4,3),(4,5),(5,6),(5,4),(8,5),(8,8),(8,7)]
Line 181 ⟶ 884:
 
println("Results in the zero-base scheme: $(inzerobase(tarj))")
</langsyntaxhighlight>{{out}}
<pre>
Results in the zero-base scheme: Array{Int64,1}[[2, 1, 0], [6, 5], [4, 3], [7]]
</pre>
 
=={{header|K}}==
Implementation:
<syntaxhighlight lang=K>F:{[g]
r::s::!i::0
t::+`o`j`k!(#g)#'0,2##g
L::{[g;v]
t[v]:1,i,i; s,:v; i+:1
{[g;v;w]
$[t[`k;w]=#g; L w; ~t[`o;w]; :0N]
t[`j;v]&:t[`j;w]}[g;v]'g v
$[=/t[`j`k;v]
[a:*&v=s; c:a_s; t[`o;c]:0; s::a#s; r,:,c]
]}[g]
{[g;v] $[t[`k;v]=#g; L v; ]}[g]'!#g
r}</syntaxhighlight>
 
Example:
 
<syntaxhighlight lang=K>F (1;2;0;1 2 4;3 5;2 6;5;4 6 7)
(0 1 2
5 6
3 4
,7)</syntaxhighlight>
 
tested with ngn/k
 
=={{header|Kotlin}}==
<langsyntaxhighlight lang="scala">// version 1.1.3
 
import java.util.Stack
Line 193 ⟶ 922:
typealias Nodes = List<Node>
 
class Node(val n: Int) {
var index = -1 // -1 signifies undefined
var lowLink = -1
Line 207 ⟶ 936:
var index = 0
val s = Stack<Node>()
 
fun strongConnect(v: Node) {
// Set the depth index for v to the smallest unused index
v.index = index
v.lowLink = index
index++
s.push(v)
v.onStack = true
 
// consider successors of v
for (w in g.es[v]!!) {
Line 236 ⟶ 965:
w.onStack = false
scc.add(w)
}
while (w != v)
sccs.add(scc)
Line 244 ⟶ 973:
for (v in g.vs) if (v.index < 0) strongConnect(v)
return sccs
}
 
fun main(args: Array<String>) {
val vs = (0..7).map { Node(it) }
val es = mapOf(
vs[0] to listOf(vs[1]),
Line 260 ⟶ 989:
val g = DirectedGraph(vs, es)
val sccs = tarjan(g)
println(sccs.joinToString("\n"))
}</langsyntaxhighlight>
 
{{out}}
Line 270 ⟶ 999:
[7]
</pre>
 
=={{header|Nim}}==
{{trans|Kotlin}}
<syntaxhighlight lang="nim">import sequtils, strutils, tables
 
type
 
Node = ref object
val: int
index: int
lowLink: int
onStack: bool
 
Nodes = seq[Node]
 
DirectedGraph = object
nodes: seq[Node]
edges: Table[int, Nodes]
 
 
func initNode(n: int): Node =
Node(val: n, index: -1, lowLink: -1, onStack: false)
 
 
func `$`(node: Node): string = $node.val
 
 
func tarjan(g: DirectedGraph): seq[Nodes] =
var index = 0
var s: seq[Node]
var sccs: seq[Nodes]
 
 
func strongConnect(v: Node) =
 
# Set the depth index for "v" to the smallest unused index.
v.index = index
v.lowLink = index
inc index
s.add v
v.onStack = true
 
# Consider successors of "v".
for w in g.edges[v.val]:
if w.index < 0:
# Successor "w" has not yet been visited; recurse on it.
w.strongConnect()
v.lowLink = min(v.lowLink, w.lowLink)
elif w.onStack:
# Successor "w" is in stack "s" and hence in the current SCC.
v.lowLink = min(v.lowLink, w.index)
 
# If "v" is a root node, pop the stack and generate an SCC.
if v.lowLink == v.index:
var scc: Nodes
while true:
let w = s.pop()
w.onStack = false
scc.add w
if w == v: break
sccs.add scc
 
 
for v in g.nodes:
if v.index < 0:
v.strongConnect()
result = move(sccs)
 
 
when isMainModule:
 
let vs = toSeq(0..7).map(initNode)
let es = {0: @[vs[1]],
1: @[vs[2]],
2: @[vs[0]],
3: @[vs[1], vs[2], vs[4]],
4: @[vs[5], vs[3]],
5: @[vs[2], vs[6]],
6: @[vs[5]],
7: @[vs[4], vs[7], vs[6]]}.toTable
var g = DirectedGraph(nodes: vs, edges: es)
let sccs = g.tarjan()
echo sccs.join("\n")</syntaxhighlight>
 
{{out}}
<pre>@[2, 1, 0]
@[6, 5]
@[4, 3]
@[7]</pre>
 
=={{header|Perl}}==
{{trans|Perl 6Raku}}
<langsyntaxhighlight lang="perl">use 5.016strict;
use feature 'state'warnings;
use feature <say state current_sub>;
use List::Util qw(min);
use experimental qw(lexical_subs);
 
sub tarjan {
Line 338 ⟶ 1,156:
print join(', ', sort @$_) . "\n" for tarjan(%test1);
print "\nStrongly connected components:\n";
print join(', ', sort @$_) . "\n" for tarjan(%test2);</langsyntaxhighlight>
{{out}}
<pre>Strongly connected components:
Line 351 ⟶ 1,169:
Dave, Earl
Hank</pre>
 
=={{header|Perl 6}}==
{{works with|Rakudo|2018.09}}
 
<lang perl6>sub tarjan (%k) {
my %onstack;
my %index;
my %lowlink;
my @stack;
my @connected;
 
sub strong-connect ($vertex) {
state $index = 0;
%index{$vertex} = $index;
%lowlink{$vertex} = $index++;
%onstack{$vertex} = True;
@stack.push: $vertex;
for |%k{$vertex} -> $connection {
if not %index{$connection}.defined {
strong-connect($connection);
%lowlink{$vertex} min= %lowlink{$connection};
}
elsif %onstack{$connection} {
%lowlink{$vertex} min= %index{$connection};
}
}
if %lowlink{$vertex} eq %index{$vertex} {
my @node;
repeat {
@node.push: @stack.pop;
%onstack{@node.tail} = False;
} while @node.tail ne $vertex;
@connected.push: @node;
}
}
 
.&strong-connect unless %index{$_} for %k.keys;
 
@connected
}
 
# TESTING
 
-> $test { say "\nStrongly connected components: ", |tarjan($test).sort».sort } for
 
# hash of vertex, edge list pairs
(((1),(2),(0),(1,2,4),(3,5),(2,6),(5),(4,6,7)).pairs.hash),
 
# Same layout test data with named vertices instead of numbered.
%(:Andy<Bart>,
:Bart<Carl>,
:Carl<Andy>,
:Dave<Bart Carl Earl>,
:Earl<Dave Fred>,
:Fred<Carl Gary>,
:Gary<Fred>,
:Hank<Earl Gary Hank>
)</lang>
{{out}}
<pre>
Strongly connected components: (0 1 2)(3 4)(5 6)(7)
 
Strongly connected components: (Andy Bart Carl)(Dave Earl)(Fred Gary)(Hank)</pre>
 
=={{header|Phix}}==
{{trans|Go}}
Same data as other examples, but with 1-based indexes.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>constant g = {{2}, {3}, {1}, {2,3,5}, {6,4}, {3,7}, {6}, {5,8,7}}
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
 
<span style="color: #008080;">constant</span> <span style="color: #000000;">g</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">6</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">}}</span>
sequence index, lowlink, stacked, stack
integer x
<span style="color: #004080;">sequence</span> <span style="color: #000000;">index</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lowlink</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">stacked</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">stack</span>
 
<span style="color: #004080;">integer</span> <span style="color: #000000;">x</span>
function strong_connect(integer n, r_emit)
index[n] = x
<span style="color: #008080;">function</span> <span style="color: #000000;">strong_connect</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">emit</span><span style="color: #0000FF;">)</span>
lowlink[n] = x
<span style="color: #000000;">index</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">x</span>
stacked[n] = 1
<span style="color: #000000;">lowlink</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">x</span>
stack &= n
<span style="color: #000000;">stacked</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
x += 1
<span style="color: #000000;">stack</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">n</span>
for b=1 to length(g[n]) do
<span style="color: #000000;">x</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
integer nb = g[n][b]
<span style="color: #008080;">for</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">g</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">do</span>
if index[nb] == 0 then
<span style="color: #004080;">integer</span> <span style="color: #000000;">nb</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">g</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">][</span><span style="color: #000000;">b</span><span style="color: #0000FF;">]</span>
if not strong_connect(nb,r_emit) then
<span style="color: #008080;">if</span> <span style="color: #000000;">index</span><span style="color: #0000FF;">[</span><span style="color: #000000;">nb</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">==</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
return false
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">strong_connect</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nb</span><span style="color: #0000FF;">,</span><span style="color: #000000;">emit</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
end if
<span style="color: #008080;">return</span> <span style="color: #004600;">false</span>
if lowlink[nb] < lowlink[n] then
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
lowlink[n] = lowlink[nb]
<span style="color: #008080;">if</span> <span style="color: #000000;">lowlink</span><span style="color: #0000FF;">[</span><span style="color: #000000;">nb</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;"><</span> <span style="color: #000000;">lowlink</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
end if
<span style="color: #000000;">lowlink</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">lowlink</span><span style="color: #0000FF;">[</span><span style="color: #000000;">nb</span><span style="color: #0000FF;">]</span>
elsif stacked[nb] == 1 then
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if index[nb] < lowlink[n] then
<span style="color: #008080;">elsif</span> <span style="color: #000000;">stacked</span><span style="color: #0000FF;">[</span><span style="color: #000000;">nb</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">==</span> <span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
lowlink[n] = index[nb]
<span style="color: #008080;">if</span> <span style="color: #000000;">index</span><span style="color: #0000FF;">[</span><span style="color: #000000;">nb</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;"><</span> <span style="color: #000000;">lowlink</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
end if
<span style="color: #000000;">lowlink</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">index</span><span style="color: #0000FF;">[</span><span style="color: #000000;">nb</span><span style="color: #0000FF;">]</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if lowlink[n] == index[n] then
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
sequence c = {}
<span style="color: #008080;">if</span> <span style="color: #000000;">lowlink</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">==</span> <span style="color: #000000;">index</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
while true do
<span style="color: #004080;">sequence</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
integer w := stack[$]
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
stack = stack[1..$-1]
<span style="color: #004080;">integer</span> <span style="color: #000000;">w</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">stack</span><span style="color: #0000FF;">[$]</span>
stacked[w] = 0
<span style="color: #000000;">stack</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">stack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
c = prepend(c, w)
<span style="color: #000000;">stacked</span><span style="color: #0000FF;">[</span><span style="color: #000000;">w</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
if w == n then
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">prepend</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">)</span>
call_proc(r_emit,{c})
<span style="color: #008080;">if</span> <span style="color: #000000;">w</span> <span style="color: #0000FF;">==</span> <span style="color: #000000;">n</span> <span style="color: #008080;">then</span>
exit
<span style="color: #000000;">emit</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
end if
<span style="color: #008080;">exit</span>
end while
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
return true
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end function
<span style="color: #008080;">return</span> <span style="color: #004600;">true</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
procedure tarjan(sequence g, integer r_emit)
index = repeat(0,length(g))
<span style="color: #008080;">procedure</span> <span style="color: #000000;">tarjan</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">g</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">emit</span><span style="color: #0000FF;">)</span>
lowlink = repeat(0,length(g))
<span style="color: #000000;">index</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">g</span><span style="color: #0000FF;">))</span>
stacked = repeat(0,length(g))
<span style="color: #000000;">lowlink</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">g</span><span style="color: #0000FF;">))</span>
stack = {}
<span style="color: #000000;">stacked</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">g</span><span style="color: #0000FF;">))</span>
x := 1
<span style="color: #000000;">stack</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
for n=1 to length(g) do
<span style="color: #000000;">x</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
if index[n] == 0
<span style="color: #008080;">for</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">g</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
and not strong_connect(n,r_emit) then
<span style="color: #008080;">if</span> <span style="color: #000000;">index</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">==</span> <span style="color: #000000;">0</span>
return
<span style="color: #008080;">and</span> <span style="color: #008080;">not</span> <span style="color: #000000;">strong_connect</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">emit</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
end if
<span style="color: #008080;">return</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end procedure
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
procedure emit(object c)
-- called for each component identified.
<span style="color: #008080;">procedure</span> <span style="color: #000000;">emit</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
-- each component is a list of nodes.
<span style="color: #000080;font-style:italic;">-- called for each component identified.
?c
-- each component is a list of nodes.</span>
end procedure
<span style="color: #0000FF;">?</span><span style="color: #000000;">c</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
tarjan(g,routine_id("emit"))</lang>
<span style="color: #000000;">tarjan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">g</span><span style="color: #0000FF;">,</span><span style="color: #000000;">emit</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 490 ⟶ 1,248:
 
=={{header|Python}}==
 
<lang python>from collections import defaultdict
===Python: As function===
<syntaxhighlight lang="python">from collections import defaultdict
 
def from_edges(edges):
Line 546 ⟶ 1,306:
for g in trajan(from_edges(table)):
print(g)
print()</langsyntaxhighlight>
{{out}}
<pre>[6, 7]
Line 556 ⟶ 1,316:
['A', 'B', 'C']
</pre>
 
===Python: As class===
This takes inspiration from the [https://www.geeksforgeeks.org/tarjan-algorithm-find-strongly-connected-components/ Geeks4Geeks explanation] and uses its five examples.
 
 
;Tx1:
<pre>
+---+ +---+ +---+ +---+
| 1 | --> | 0 | --> | 3 | --> | 4 |
+---+ +---+ +---+ +---+
^ |
| |
| v
| +---+
+------ | 2 |
+---+
</pre>
 
;Tx2:
<pre>
+---+ +---+ +---+ +---+
| 0 | --> | 1 | --> | 2 | --> | 3 |
+---+ +---+ +---+ +---+
</pre>
 
;Tx3:
<pre>
 
+----------------------------------+
v |
+---+ +---+ +---+ +---+ |
| 0 | --> | | --> | 3 | --> | 5 | |
+---+ | | +---+ +---+ |
| | ^ |
| 1 | | |
| | | |
+---+ | | +---+ | |
| 6 | <-- | | --> | 2 | ------+----+
+---+ +---+ +---+ |
| |
| |
v |
+---+ |
| 4 | ----------------+
+---+
</pre>
 
;Tx4:
<pre>
 
+-----------------------------+
| |
| +---+ |
| | A | | +-------------------+
| +---+ | | |
| | | |
| +---------+---------+---------+ | +---------+
| | v v v | v |
+---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
| 3 | <-- | 0 | --> | 1 | --> | 2 | --> | 6 | --> | 4 | --> | | --> | 7 | --> | 9 | --> | 8 |
+---+ +---+ +---+ +---+ +---+ +---+ | | +---+ +---+ +---+
^ | ^ | | | ^ ^
+-------------------+ +---------+ | 5 | ----------------+ |
| | |
| | |
| | --------------------------+
+---+
</pre>
 
;Tx5:
<pre>
 
+--------------+
| |
| |
+-------------------+---------+ |
v v | |
+---+ +---+ +---+ +---+ |
| 0 | --> | 1 | --> | 2 | --> | 3 | |
+---+ +---+ +---+ +---+ |
| |
| |
v |
+---+ |
| 4 | -----------+
+---+
</pre>
 
;Code:
<syntaxhighlight lang="python">from collections import defaultdict
 
 
class Graph:
"Directed Graph Tarjan's strongly connected components algorithm"
 
def __init__(self, name, connections):
self.name = name
self.connections = connections
g = defaultdict(list) # map node vertex to direct connections
for n1, n2 in connections:
if n1 != n2:
g[n1].append(n2)
else:
g[n1]
for _, n2 in connections:
g[n2] # For leaf nodes having no edges from themselves
self.graph = dict(g)
self.tarjan_algo()
 
def _visitor(self, this, low, disc, stack):
'''
Recursive function that finds SCC's
using DFS traversal of vertices.
 
Arguments:
this --> Vertex to be visited in this call.
disc{} --> Discovery order of visited vertices.
low{} --> Connected vertex of earliest discovery order
stack --> Ancestor node stack during DFS.
'''
 
disc[this] = low[this] = self._order
self._order += 1
stack.append(this)
 
for neighbr in self.graph[this]:
if neighbr not in disc:
# neighbour not visited so do DFS recurrence.
self._visitor(neighbr, low, disc, stack)
low[this] = min(low[this], low[neighbr]) # Prior connection?
 
elif neighbr in stack:
# Update low value of this only if neighbr in stack
low[this] = min(low[this], disc[neighbr])
 
if low[this] == disc[this]:
# Head node found of SCC
top, new = None, []
while top != this:
top = stack.pop()
new.append(top)
self.scc.append(new)
 
def tarjan_algo(self):
'''
Recursive function that finds strongly connected components
using the Tarjan Algorithm and function _visitor() to visit nodes.
'''
 
self._order = 0 # Visitation order counter
disc, low = {}, {}
stack = []
 
self.scc = [] # SCC result accumulator
for vertex in sorted(self.graph):
if vertex not in disc:
self._visitor(vertex, low, disc, stack)
self._disc, self._low = disc, low
 
 
if __name__ == '__main__':
for n, m in [('Tx1', '10 02 21 03 34'.split()),
('Tx2', '01 12 23'.split()),
('Tx3', '01 12 20 13 14 16 35 45'.split()),
('Tx4', '01 03 12 14 20 26 32 45 46 56 57 58 59 64 79 89 98 AA'.split()),
('Tx5', '01 12 23 24 30 42'.split()),
]:
print(f"\n\nGraph({repr(n)}, {m}):\n")
g = Graph(n, m)
print(" : ", ' '.join(str(v) for v in sorted(g._disc)))
print(" DISC of", g.name + ':', [v for _, v in sorted(g._disc.items())])
print(" LOW of", g.name + ':', [v for _, v in sorted(g._low.items())])
scc = repr(g.scc if g.scc else '').replace("'", '').replace(',', '')[1:-1]
print("\n SCC's of", g.name + ':', scc)</syntaxhighlight>
 
{{out}}
 
<pre>Graph('Tx1', ['10', '02', '21', '03', '34']):
 
: 0 1 2 3 4
DISC of Tx1: [0, 2, 1, 3, 4]
LOW of Tx1: [0, 0, 0, 3, 4]
 
SCC's of Tx1: [4] [3] [1 2 0]
 
 
Graph('Tx2', ['01', '12', '23']):
 
: 0 1 2 3
DISC of Tx2: [0, 1, 2, 3]
LOW of Tx2: [0, 1, 2, 3]
 
SCC's of Tx2: [3] [2] [1] [0]
 
 
Graph('Tx3', ['01', '12', '20', '13', '14', '16', '35', '45']):
 
: 0 1 2 3 4 5 6
DISC of Tx3: [0, 1, 2, 3, 5, 4, 6]
LOW of Tx3: [0, 0, 0, 3, 5, 4, 6]
 
SCC's of Tx3: [5] [3] [4] [6] [2 1 0]
 
 
Graph('Tx4', ['01', '03', '12', '14', '20', '26', '32', '45', '46', '56', '57', '58', '59', '64', '79', '89', '98', 'AA']):
 
: 0 1 2 3 4 5 6 7 8 9 A
DISC of Tx4: [0, 1, 2, 9, 4, 5, 3, 6, 8, 7, 10]
LOW of Tx4: [0, 0, 0, 2, 3, 3, 3, 6, 7, 7, 10]
 
SCC's of Tx4: [8 9] [7] [5 4 6] [3 2 1 0] [A]
 
 
Graph('Tx5', ['01', '12', '23', '24', '30', '42']):
 
: 0 1 2 3 4
DISC of Tx5: [0, 1, 2, 3, 4]
LOW of Tx5: [0, 0, 0, 0, 2]
 
SCC's of Tx5: [4 3 2 1 0]</pre>
 
=={{header|Racket}}==
Line 563 ⟶ 1,543:
{{trans|Kotlin}}
 
<langsyntaxhighlight lang="racket">#lang racket
 
(require syntax/parse/define
Line 611 ⟶ 1,591:
(define store (make-hash))
(define (make-node v) (hash-ref! store v (thunk (node v #f #f #f))))
 
;; it's important that we use hasheq instead of hash so that we compare
;; reference instead of actual value. Had we use the actual value,
Line 624 ⟶ 1,604:
[3 1 2 4]
[4 5 3]
[7 4 7 6])))</langsyntaxhighlight>
 
{{out}}
Line 634 ⟶ 1,614:
=== With the graph library ===
 
<langsyntaxhighlight lang="racket">#lang racket
 
(require graph)
Line 647 ⟶ 1,627:
[7 4 7 6])))
 
(scc g)</langsyntaxhighlight>
 
{{out}}
<pre>
'((7) (3 4) (5 6) (1 0 2))
</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2018.09}}
 
<syntaxhighlight lang="raku" line>sub tarjan (%k) {
my %onstack;
my %index;
my %lowlink;
my @stack;
my @connected;
 
sub strong-connect ($vertex) {
state $index = 0;
%index{$vertex} = $index;
%lowlink{$vertex} = $index++;
%onstack{$vertex} = True;
@stack.push: $vertex;
for |%k{$vertex} -> $connection {
if not %index{$connection}.defined {
strong-connect($connection);
%lowlink{$vertex} min= %lowlink{$connection};
}
elsif %onstack{$connection} {
%lowlink{$vertex} min= %index{$connection};
}
}
if %lowlink{$vertex} eq %index{$vertex} {
my @node;
repeat {
@node.push: @stack.pop;
%onstack{@node.tail} = False;
} while @node.tail ne $vertex;
@connected.push: @node;
}
}
 
.&strong-connect unless %index{$_} for %k.keys;
 
@connected
}
 
# TESTING
 
-> $test { say "\nStrongly connected components: ", |tarjan($test).sort».sort } for
 
# hash of vertex, edge list pairs
(((1),(2),(0),(1,2,4),(3,5),(2,6),(5),(4,6,7)).pairs.hash),
 
# Same layout test data with named vertices instead of numbered.
%(:Andy<Bart>,
:Bart<Carl>,
:Carl<Andy>,
:Dave<Bart Carl Earl>,
:Earl<Dave Fred>,
:Fred<Carl Gary>,
:Gary<Fred>,
:Hank<Earl Gary Hank>
)</syntaxhighlight>
{{out}}
<pre>
Strongly connected components: (0 1 2)(3 4)(5 6)(7)
 
Strongly connected components: (Andy Bart Carl)(Dave Earl)(Fred Gary)(Hank)</pre>
 
=={{header|REXX}}==
<syntaxhighlight lang="rexx">/* REXX - Tarjan's Algorithm */
/* Vertices are numbered 1 to 8 (instead of 0 to 7) */
g='[2] [3] [1] [2 3 5] [4 6] [3 7] [6] [5 7 8]'
gg=g
Do i=1 By 1 While gg>''
Parse Var gg '[' g.i ']' gg
name.i=i-1
End
g.0=i-1
index.=0
lowlink.=0
stacked.=0
stack.=0
x=1
Do n=1 To g.0
If index.n=0 Then
If strong_connect(n)=0 Then
Return
End
Exit
 
strong_connect: Procedure Expose x g. index. lowlink. stacked. stack. name.
Parse Arg n
index.n = x
lowlink.n = x
stacked.n = 1
Call stack n
x=x+1
Do b=1 To words(g.n)
Call show_all
nb=word(g.n,b)
If index.nb=0 Then Do
If strong_connect(nb)=0 Then
Return 0
If lowlink.nb < lowlink.n Then
lowlink.n = lowlink.nb
End
Else Do
If stacked.nb = 1 Then
If index.nb < lowlink.n Then
lowlink.n = index.nb
end
end
if lowlink.n=index.n then Do
c=''
Do z=stack.0 By -1
w=stack.z
stacked.w=0
stack.0=stack.0-1
c=name.w c
If w=n Then Do
Say '['space(c)']'
Return 1
End
End
End
Return 1
 
stack: Procedure Expose stack.
Parse Arg m
z=stack.0+1
stack.z=m
stack.0=z
Return
 
/* The following were used for debugging (and understanding) */
 
show_all: Return
ind='Index '
low='Lowlink'
sta='Stacked'
Do z=1 To g.0
ind=ind index.z
low=low lowlink.z
sta=sta stacked.z
End
Say ind
Say low
Say sta
Return
 
show_stack:
ol='Stack'
Do z=1 To stack.0
ol=ol stack.z
End
Say ol
Return</syntaxhighlight>
{{out}}
<pre>[0 1 2]
[5 6]
[3 4]
[7]</pre>
 
=={{header|Rust}}==
<syntaxhighlight lang="rust">use std::collections::{BTreeMap, BTreeSet};
 
// Using a naked BTreeMap would not be very nice, so let's make a simple graph representation
#[derive(Clone, Debug)]
pub struct Graph {
neighbors: BTreeMap<usize, BTreeSet<usize>>,
}
 
impl Graph {
pub fn new(size: usize) -> Self {
Self {
neighbors: (0..size).fold(BTreeMap::new(), |mut acc, x| {
acc.insert(x, BTreeSet::new());
acc
}),
}
}
 
pub fn edges<'a>(&'a self, vertex: usize) -> impl Iterator<Item = usize> + 'a {
self.neighbors[&vertex].iter().cloned()
}
 
pub fn add_edge(&mut self, from: usize, to: usize) {
assert!(to < self.len());
self.neighbors.get_mut(&from).unwrap().insert(to);
}
 
pub fn add_edges(&mut self, from: usize, to: impl IntoIterator<Item = usize>) {
let limit = self.len();
 
self.neighbors
.get_mut(&from)
.unwrap()
.extend(to.into_iter().filter(|x| {
assert!(*x < limit);
true
}));
}
 
pub fn is_empty(&self) -> bool {
self.neighbors.is_empty()
}
 
pub fn len(&self) -> usize {
self.neighbors.len()
}
}
 
#[derive(Clone)]
struct VertexState {
index: usize,
low_link: usize,
on_stack: bool,
}
 
// The easy way not to fight with Rust's borrow checker is moving the state in
// a structure and simply invoke methods on that structure.
 
pub struct Tarjan<'a> {
graph: &'a Graph,
index: usize,
stack: Vec<usize>,
state: Vec<VertexState>,
components: Vec<BTreeSet<usize>>,
}
 
impl<'a> Tarjan<'a> {
// Having index: Option<usize> would look nicer, but requires just
// some unwraps and Vec has actual len limit isize::MAX anyway, so
// we can reserve this large value as the invalid one.
const INVALID_INDEX: usize = usize::MAX;
 
pub fn walk(graph: &'a Graph) -> Vec<BTreeSet<usize>> {
Self {
graph,
index: 0,
stack: Vec::new(),
state: vec![
VertexState {
index: Self::INVALID_INDEX,
low_link: Self::INVALID_INDEX,
on_stack: false
};
graph.len()
],
components: Vec::new(),
}
.visit_all()
}
 
fn visit_all(mut self) -> Vec<BTreeSet<usize>> {
for vertex in 0..self.graph.len() {
if self.state[vertex].index == Self::INVALID_INDEX {
self.visit(vertex);
}
}
 
self.components
}
 
fn visit(&mut self, v: usize) {
let v_ref = &mut self.state[v];
v_ref.index = self.index;
v_ref.low_link = self.index;
self.index += 1;
self.stack.push(v);
v_ref.on_stack = true;
 
for w in self.graph.edges(v) {
let w_ref = &self.state[w];
if w_ref.index == Self::INVALID_INDEX {
self.visit(w);
let w_low_link = self.state[w].low_link;
let v_ref = &mut self.state[v];
v_ref.low_link = v_ref.low_link.min(w_low_link);
} else if w_ref.on_stack {
let w_index = self.state[w].index;
let v_ref = &mut self.state[v];
v_ref.low_link = v_ref.low_link.min(w_index);
}
}
 
let v_ref = &self.state[v];
if v_ref.low_link == v_ref.index {
let mut component = BTreeSet::new();
 
loop {
let w = self.stack.pop().unwrap();
self.state[w].on_stack = false;
component.insert(w);
if w == v {
break;
}
}
 
self.components.push(component);
}
}
}
 
fn main() {
let graph = {
let mut g = Graph::new(8);
g.add_edge(0, 1);
g.add_edge(2, 0);
g.add_edges(5, vec![2, 6]);
g.add_edge(6, 5);
g.add_edge(1, 2);
g.add_edges(3, vec![1, 2, 4]);
g.add_edges(4, vec![5, 3]);
g.add_edges(7, vec![4, 7, 6]);
g
};
 
for component in Tarjan::walk(&graph) {
println!("{:?}", component);
}
}</syntaxhighlight>
 
{{out}}
<pre>
{0, 1, 2}
{5, 6}
{3, 4}
{7}
</pre>
 
=={{header|Sidef}}==
{{trans|Perl 6Raku}}
<langsyntaxhighlight lang="ruby">func tarjan (k) {
 
var(:onstack, :index, :lowlink, *stack, *connected)
Line 717 ⟶ 2,024:
tests.each {|t|
say ("Strongly connected components: ", tarjan(t).map{.sort}.sort)
}</langsyntaxhighlight>
{{out}}
<pre>
Strongly connected components: [["0", "1", "2"], ["3", "4"], ["5", "6"], ["7"]]
Strongly connected components: [["Andy", "Bart", "Carl"], ["Dave", "Earl"], ["Fred", "Gary"], ["Hank"]]
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-seq}}
{{libheader|Wren-dynamic}}
<syntaxhighlight lang="wren">import "./seq" for Stack
import "./dynamic" for Tuple
 
class Node {
construct new(n) {
_n = n
_index = -1 // -1 signifies undefined
_lowLink = -1
_onStack = false
}
 
n { _n }
index { _index }
index=(v) { _index = v }
lowLink { _lowLink }
lowLink=(v) { _lowLink = v }
onStack { _onStack }
onStack=(v) { _onStack = v }
 
toString { _n.toString }
}
 
var DirectedGraph = Tuple.create("DirectedGraph", ["vs", "es"])
 
var tarjan = Fn.new { |g|
var sccs = []
var index = 0
var s = Stack.new()
 
var strongConnect // recursive closure
strongConnect = Fn.new { |v|
// Set the depth index for v to the smallest unused index
v.index = index
v.lowLink = index
index = index + 1
s.push(v)
v.onStack = true
 
// consider successors of v
for (w in g.es[v.n]) {
if (w.index < 0) {
// Successor w has not yet been visited; recurse on it
strongConnect.call(w)
v.lowLink = v.lowLink.min(w.lowLink)
} else if (w.onStack) {
// Successor w is in stack s and hence in the current SCC
v.lowLink = v.lowLink.min(w.index)
}
}
 
// If v is a root node, pop the stack and generate an SCC
if (v.lowLink == v.index) {
var scc = []
while (true) {
var w = s.pop()
w.onStack = false
scc.add(w)
if (w == v) break
}
sccs.add(scc)
}
}
 
for (v in g.vs) if (v.index < 0) strongConnect.call(v)
return sccs
}
 
var vs = (0..7).map { |i| Node.new(i) }.toList
var es = {
0: [vs[1]],
2: [vs[0]],
5: [vs[2], vs[6]],
6: [vs[5]],
1: [vs[2]],
3: [vs[1], vs[2], vs[4]],
4: [vs[5], vs[3]],
7: [vs[4], vs[7], vs[6]]
}
var g = DirectedGraph.new(vs, es)
var sccs = tarjan.call(g)
System.print(sccs.join("\n"))</syntaxhighlight>
 
{{out}}
<pre>
[2, 1, 0]
[6, 5]
[4, 3]
[7]
</pre>
 
=={{header|zkl}}==
<langsyntaxhighlight lang="zkl">class Tarjan{
// input: graph G = (V, Es)
// output: set of strongly connected components (sets of vertices)
Line 731 ⟶ 2,132:
const INDEX=0, LOW_LINK=1, ON_STACK=2;
fcn init(graph){
var index=0, stack=List(), components=List(),
G=List.createLong(graph.len(),0);
 
Line 743 ⟶ 2,144:
foreach c in (components){ println(c.reverse().concat(",")) }
 
returnClass(components); // over-ride return of class instance
}
fcn strongConnect(v){ // v is ( (index,lowlink,onStack), (id,links) )
Line 754 ⟶ 2,155:
// Consider successors of v
foreach idx in (v[1][1,*]){ // links of v to other vs
w,w0 := G[idx],w[0]; // well, that is pretty vile
if(w[0][INDEX]==Void){
strongConnect(w); // Successor w not yet visited; recurse on it
v0[LOW_LINK]=v0[LOW_LINK].min(w0[LOW_LINK]);
}
else if(w0[ON_STACK])
// Successor w is in stack S and hence in the current SCC
v0[LOW_LINK]=v0[LOW_LINK].min(w0[INDEX]);
}
// If v is a root node, pop the stack and generate an SCC
if(v0[LOW_LINK]==v0[INDEX]){
strong:=List(); // start a new strongly connected component
do{
w,w0 := stack.pop(), w[0];
w0[ON_STACK]=False;
strong.append(w[1][0]); // add w to strongly connected component
}while(w.id!=v.id);
components.append(strong); // output strongly connected component
}
}
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl"> // graph from https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
// with vertices id zero based (vs 1 based in article)
// ids start at zero and are consecutive (no holes), graph is unsorted
graph:= // ( (id, links/Edges), ...)
T( T(0,1), T(2,0), T(5,2,6), T(6,5),
T(1,2), T(3,1,2,4), T(4,5,3), T(7,4,7,6) );
Tarjan(graph);</langsyntaxhighlight>
{{out}}
<pre>
9,476

edits