1
+
2
+ /**
3
+ * An implementation of Tarjan's Strongly Connected Components algorithm using an adjacency list.
4
+ *
5
+ * <p>Time complexity: O(V+E)
6
+ *
7
+ * @author William Fiset, william.alexandre.fiset@gmail.com
8
+ */
9
+
10
+ import static java .lang .Math .min ;
11
+
12
+ import java .util .*;
13
+
14
+ public class TarjanScc {
15
+
16
+ private int n ;
17
+ private List <List <Integer >> graph ;
18
+
19
+ private boolean solved ;
20
+ private int sccCount , id ;
21
+ private boolean [] onStack ;
22
+ private int [] ids , low ;
23
+ private Deque <Integer > stack ;
24
+
25
+ private static final int UNVISITED = -1 ;
26
+
27
+ public TarjanScc (List <List <Integer >> graph ) {
28
+ if (graph == null ) throw new IllegalArgumentException ("Graph cannot be null." );
29
+ n = graph .size ();
30
+ this .graph = graph ;
31
+ }
32
+
33
+ // Returns the number of strongly connected components in the graph.
34
+ public int sccCount () {
35
+ if (!solved ) solve ();
36
+ return sccCount ;
37
+ }
38
+
39
+ // Get the connected components of this graph. If two indexes
40
+ // have the same value then they're in the same SCC.
41
+ public int [] getSccs () {
42
+ if (!solved ) solve ();
43
+ return low ;
44
+ }
45
+
46
+ public void solve () {
47
+ if (solved ) return ;
48
+
49
+ ids = new int [n ];
50
+ low = new int [n ];
51
+ onStack = new boolean [n ];
52
+ stack = new ArrayDeque <>();
53
+ Arrays .fill (ids , UNVISITED );
54
+
55
+ for (int i = 0 ; i < n ; i ++) if (ids [i ] == UNVISITED ) dfs (i );
56
+
57
+ solved = true ;
58
+ }
59
+
60
+ private void dfs (int at ) {
61
+ stack .push (at );
62
+ onStack [at ] = true ;
63
+ ids [at ] = low [at ] = id ++;
64
+
65
+ for (int to : graph .get (at )) {
66
+ if (ids [to ] == UNVISITED ) dfs (to );
67
+ if (onStack [to ]) low [at ] = min (low [at ], low [to ]);
68
+ }
69
+
70
+ // On recursive callback, if we're at the root node (start of SCC)
71
+ // empty the seen stack until back to root.
72
+ if (ids [at ] == low [at ]) {
73
+ for (int node = stack .pop (); ; node = stack .pop ()) {
74
+ onStack [node ] = false ;
75
+ low [node ] = ids [at ];
76
+ if (node == at ) break ;
77
+ }
78
+ sccCount ++;
79
+ }
80
+ }
81
+
82
+ // Initializes adjacency list with n nodes.
83
+ public static List <List <Integer >> createGraph (int n ) {
84
+ List <List <Integer >> graph = new ArrayList <>(n );
85
+ for (int i = 0 ; i < n ; i ++) graph .add (new ArrayList <>());
86
+ return graph ;
87
+ }
88
+
89
+ // Adds a directed edge from node 'from' to node 'to'
90
+ public static void addEdge (List <List <Integer >> graph , int from , int to ) {
91
+ graph .get (from ).add (to );
92
+ }
93
+
94
+ /* Example usage: */
95
+
96
+ public static void main (String [] arg ) {
97
+ int n = 8 ;
98
+ List <List <Integer >> graph = createGraph (n );
99
+
100
+ addEdge (graph , 6 , 0 );
101
+ addEdge (graph , 6 , 2 );
102
+ addEdge (graph , 3 , 4 );
103
+ addEdge (graph , 6 , 4 );
104
+ addEdge (graph , 2 , 0 );
105
+ addEdge (graph , 0 , 1 );
106
+ addEdge (graph , 4 , 5 );
107
+ addEdge (graph , 5 , 6 );
108
+ addEdge (graph , 3 , 7 );
109
+ addEdge (graph , 7 , 5 );
110
+ addEdge (graph , 1 , 2 );
111
+ addEdge (graph , 7 , 3 );
112
+ addEdge (graph , 5 , 0 );
113
+
114
+ TarjanScc solver = new TarjanScc (graph );
115
+
116
+ int [] sccs = solver .getSccs ();
117
+ Map <Integer , List <Integer >> multimap = new HashMap <>();
118
+ for (int i = 0 ; i < n ; i ++) {
119
+ if (!multimap .containsKey (sccs [i ])) multimap .put (sccs [i ], new ArrayList <>());
120
+ multimap .get (sccs [i ]).add (i );
121
+ }
122
+
123
+ // Prints:
124
+ // Number of Strongly Connected Components: 3
125
+ // Nodes: [0, 1, 2] form a Strongly Connected Component.
126
+ // Nodes: [3, 7] form a Strongly Connected Component.
127
+ // Nodes: [4, 5, 6] form a Strongly Connected Component.
128
+ System .out .printf ("Number of Strongly Connected Components: %d\n " , solver .sccCount ());
129
+ for (List <Integer > scc : multimap .values ()) {
130
+ System .out .println ("Nodes: " + scc + " form a Strongly Connected Component." );
131
+ }
132
+ }
133
+ }
0 commit comments