You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

280 lines
8.3 KiB
Java

package de.normalisiert.utils.graphs;
import java.util.Vector;
/**
* This is a helpclass for the search of all elementary cycles in a graph
* with the algorithm of Johnson. For this it searches for strong connected
* components, using the algorithm of Tarjan. The constructor gets an
* adjacency-list of a graph. Based on this graph, it gets a nodenumber s,
* for which it calculates the subgraph, containing all nodes
* {s, s + 1, ..., n}, where n is the highest nodenumber in the original
* graph (e.g. it builds a subgraph with all nodes with higher or same
* nodenumbers like the given node s). It returns the strong connected
* component of this subgraph which contains the lowest nodenumber of all
* nodes in the subgraph.<br><br>
*
* For a description of the algorithm for calculating the strong connected
* components see:<br>
* Robert Tarjan: Depth-first search and linear graph algorithms. In: SIAM
* Journal on Computing. Volume 1, Nr. 2 (1972), pp. 146-160.<br>
* For a description of the algorithm for searching all elementary cycles in
* a directed graph see:<br>
* Donald B. Johnson: Finding All the Elementary Circuits of a Directed Graph.
* SIAM Journal on Computing. Volumne 4, Nr. 1 (1975), pp. 77-84.<br><br>
*
* @author Frank Meyer, web_at_normalisiert_dot_de
* @version 1.1, 22.03.2009
*
*/
public class StrongConnectedComponents {
/** Adjacency-list of original graph */
private int[][] adjListOriginal = null;
/** Adjacency-list of currently viewed subgraph */
private int[][] adjList = null;
/** Helpattribute for finding scc's */
private boolean[] visited = null;
/** Helpattribute for finding scc's */
private Vector stack = null;
/** Helpattribute for finding scc's */
private int[] lowlink = null;
/** Helpattribute for finding scc's */
private int[] number = null;
/** Helpattribute for finding scc's */
private int sccCounter = 0;
/** Helpattribute for finding scc's */
private Vector currentSCCs = null;
/**
* Constructor.
*
* @param adjList adjacency-list of the graph
*/
public StrongConnectedComponents(int[][] adjList) {
this.adjListOriginal = adjList;
}
/**
* This method returns the adjacency-structure of the strong connected
* component with the least vertex in a subgraph of the original graph
* induced by the nodes {s, s + 1, ..., n}, where s is a given node. Note
* that trivial strong connected components with just one node will not
* be returned.
*
* @param node node s
* @return SCCResult with adjacency-structure of the strong
* connected component; null, if no such component exists
*/
public SCCResult getAdjacencyList(int node) {
this.visited = new boolean[this.adjListOriginal.length];
this.lowlink = new int[this.adjListOriginal.length];
this.number = new int[this.adjListOriginal.length];
this.visited = new boolean[this.adjListOriginal.length];
this.stack = new Vector();
this.currentSCCs = new Vector();
this.makeAdjListSubgraph(node);
for (int i = node; i < this.adjListOriginal.length; i++) {
if (!this.visited[i]) {
this.getStrongConnectedComponents(i);
Vector nodes = this.getLowestIdComponent();
if (nodes != null && !nodes.contains(new Integer(node)) && !nodes.contains(new Integer(node + 1))) {
return this.getAdjacencyList(node + 1);
} else {
Vector[] adjacencyList = this.getAdjList(nodes);
if (adjacencyList != null) {
for (int j = 0; j < this.adjListOriginal.length; j++) {
if (adjacencyList[j].size() > 0) {
return new SCCResult(adjacencyList, j);
}
}
}
}
}
}
return null;
}
/**
* Builds the adjacency-list for a subgraph containing just nodes
* >= a given index.
*
* @param node Node with lowest index in the subgraph
*/
private void makeAdjListSubgraph(int node) {
this.adjList = new int[this.adjListOriginal.length][0];
for (int i = node; i < this.adjList.length; i++) {
Vector successors = new Vector();
for (int j = 0; j < this.adjListOriginal[i].length; j++) {
if (this.adjListOriginal[i][j] >= node) {
successors.add(new Integer(this.adjListOriginal[i][j]));
}
}
if (successors.size() > 0) {
this.adjList[i] = new int[successors.size()];
for (int j = 0; j < successors.size(); j++) {
Integer succ = (Integer) successors.get(j);
this.adjList[i][j] = succ.intValue();
}
}
}
}
/**
* Calculates the strong connected component out of a set of scc's, that
* contains the node with the lowest index.
*
* @return Vector::Integer of the scc containing the lowest nodenumber
*/
private Vector getLowestIdComponent() {
int min = this.adjList.length;
Vector currScc = null;
for (int i = 0; i < this.currentSCCs.size(); i++) {
Vector scc = (Vector) this.currentSCCs.get(i);
for (int j = 0; j < scc.size(); j++) {
Integer node = (Integer) scc.get(j);
if (node.intValue() < min) {
currScc = scc;
min = node.intValue();
}
}
}
return currScc;
}
/**
* @return Vector[]::Integer representing the adjacency-structure of the
* strong connected component with least vertex in the currently viewed
* subgraph
*/
private Vector[] getAdjList(Vector nodes) {
Vector[] lowestIdAdjacencyList = null;
if (nodes != null) {
lowestIdAdjacencyList = new Vector[this.adjList.length];
for (int i = 0; i < lowestIdAdjacencyList.length; i++) {
lowestIdAdjacencyList[i] = new Vector();
}
for (int i = 0; i < nodes.size(); i++) {
int node = ((Integer) nodes.get(i)).intValue();
for (int j = 0; j < this.adjList[node].length; j++) {
int succ = this.adjList[node][j];
if (nodes.contains(new Integer(succ))) {
lowestIdAdjacencyList[node].add(new Integer(succ));
}
}
}
}
return lowestIdAdjacencyList;
}
/**
* Searchs for strong connected components reachable from a given node.
*
* @param root node to start from.
*/
private void getStrongConnectedComponents(int root) {
this.sccCounter++;
this.lowlink[root] = this.sccCounter;
this.number[root] = this.sccCounter;
this.visited[root] = true;
this.stack.add(new Integer(root));
for (int i = 0; i < this.adjList[root].length; i++) {
int w = this.adjList[root][i];
if (!this.visited[w]) {
this.getStrongConnectedComponents(w);
this.lowlink[root] = Math.min(lowlink[root], lowlink[w]);
} else if (this.number[w] < this.number[root]) {
if (this.stack.contains(new Integer(w))) {
lowlink[root] = Math.min(this.lowlink[root], this.number[w]);
}
}
}
// found scc
if ((lowlink[root] == number[root]) && (stack.size() > 0)) {
int next = -1;
Vector scc = new Vector();
do {
next = ((Integer) this.stack.get(stack.size() - 1)).intValue();
this.stack.remove(stack.size() - 1);
scc.add(new Integer(next));
} while (this.number[next] > this.number[root]);
// simple scc's with just one node will not be added
if (scc.size() > 1) {
this.currentSCCs.add(scc);
}
}
}
public static void main(String[] args) {
boolean[][] adjMatrix = new boolean[10][];
for (int i = 0; i < 10; i++) {
adjMatrix[i] = new boolean[10];
}
/*adjMatrix[0][1] = true;
adjMatrix[1][2] = true;
adjMatrix[2][0] = true;
adjMatrix[2][4] = true;
adjMatrix[1][3] = true;
adjMatrix[3][6] = true;
adjMatrix[6][5] = true;
adjMatrix[5][3] = true;
adjMatrix[6][7] = true;
adjMatrix[7][8] = true;
adjMatrix[7][9] = true;
adjMatrix[9][6] = true;*/
adjMatrix[0][1] = true;
adjMatrix[1][2] = true;
adjMatrix[2][0] = true; adjMatrix[2][6] = true;
adjMatrix[3][4] = true;
adjMatrix[4][5] = true; adjMatrix[4][6] = true;
adjMatrix[5][3] = true;
adjMatrix[6][7] = true;
adjMatrix[7][8] = true;
adjMatrix[8][6] = true;
adjMatrix[6][1] = true;
int[][] adjList = AdjacencyList.getAdjacencyList(adjMatrix);
StrongConnectedComponents scc = new StrongConnectedComponents(adjList);
for (int i = 0; i < adjList.length; i++) {
System.out.print("i: " + i + "\n");
SCCResult r = scc.getAdjacencyList(i);
if (r != null) {
Vector[] al = scc.getAdjacencyList(i).getAdjList();
for (int j = i; j < al.length; j++) {
if (al[j].size() > 0) {
System.out.print("j: " + j);
for (int k = 0; k < al[j].size(); k++) {
System.out.print(" _" + al[j].get(k).toString());
}
System.out.print("\n");
}
}
System.out.print("\n");
}
}
}
}