void (@NotNull List<? super List<Node>> sccs, Node[] allNodes) { int successor = -1; nextNode: while (!frames.isEmpty()) { TarjanFrame<Node> pair = frames.peekLast(); int i = pair.nodeI; // we have returned to the node if (index[i] == -1) { // actually, we visit node first time, prepare index[i] = dfsIndex; lowLink[i] = dfsIndex; dfsIndex++; nodesOnStack.push(i); isOnStack[i] = true; } if (ArrayUtil.indexOf(pair.out, successor) != -1) { lowLink[i] = Math.min(lowLink[i], lowLink[successor]); } successor = i; // if unexplored children left, dfs there while (pair.nextUnexploredIndex < pair.out.length) { int nextI = pair.out[pair.nextUnexploredIndex++]; if (index[nextI] == -1) { frames.addLast(new TarjanFrame<>(nextI, allNodes, buildOuts(allNodes[nextI]))); continue nextNode; } if (isOnStack[nextI]) { lowLink[i] = Math.min(lowLink[i], index[nextI]); if (myBackEdge == null) { myBackEdge = new AbstractMap.SimpleImmutableEntry<>(allNodes[nextI], allNodes[i]); } } } frames.removeLast(); topo.add(i); // we are really back, pop a scc if (lowLink[i] == index[i]) { // found yer List<Node> scc = new ArrayList<>(); int pushedI; do { pushedI = nodesOnStack.popInt(); Node pushed = allNodes[pushedI]; isOnStack[pushedI] = false; scc.add(pushed); } while (pushedI != i); sccs.add(scc); } } }