/*
* This file is part of the Trickl Open Source Libraries.
*
* Trickl Open Source Libraries - http://open.trickl.com/
*
* Copyright (C) 2011 Tim Gee.
*
* Trickl Open Source Libraries are free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Trickl Open Source Libraries are distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this project. If not, see <http://www.gnu.org/licenses/>.
*/
package com.trickl.graph;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import org.jgrapht.Graph;
public class DepthFirstSearch<V, E> {
private static class Context<V, E> {
protected V vertex;
protected Iterator<E> edgeItr;
public Context(V vertex, Iterator<E> edgeItr) {
this.vertex = vertex;
this.edgeItr = edgeItr;
}
}
private enum Color {
WHITE,
GRAY,
BLACK;
}
Stack<Context> order = new Stack<Context>();
private Graph<V, E> graph;
public DepthFirstSearch(Graph<V, E> graph) {
this.graph = graph;
}
public void traverse(SpanningSearchVisitor<V, E> visitor) {
Iterator<V> vertexIterator = graph.vertexSet().iterator();
if (!vertexIterator.hasNext()) return;
else traverse(vertexIterator.next(), visitor);
}
public void traverse(V startVertex,
SpanningSearchVisitor<V, E> visitor) {
// Initialize the color map
Map<V, Color> colorMap = new Hashtable<V, Color>(graph.vertexSet().size());
for (V u : graph.vertexSet()) {
colorMap.put(u, Color.WHITE);
visitor.initializeVertex(u);
}
visitor.startVertex(startVertex);
order.clear();
traverseImpl(startVertex, visitor, colorMap);
// The graph may be disconnected - search untouched disjoint sets
for (V u : graph.vertexSet()) {
Color color = colorMap.get(u);
if (color == Color.WHITE) {
visitor.startVertex(u);
order.clear();
traverseImpl(u, visitor, colorMap);
}
}
}
private void traverseImpl(V startVertex,
SpanningSearchVisitor<V, E> visitor,
Map<V, Color> colorMap) {
V u = startVertex;
colorMap.put(u, Color.GRAY);
visitor.discoverVertex(u);
order.add(new Context<V, E>(u, graph.edgesOf(u).iterator()));
while (!order.isEmpty()) {
Context<V, E> context = order.pop();
u = context.vertex;
Iterator<E> edgeItr = context.edgeItr;
while (edgeItr.hasNext()) {
E e = edgeItr.next();
V v = graph.getEdgeTarget(e).equals(u) ?
graph.getEdgeSource(e) :
graph.getEdgeTarget(e);
// Check if a directed edge in the wrong direction
if (!graph.containsEdge(u, v)) continue;
visitor.examineEdge(u, v);
Color color = colorMap.get(v);
if (color == Color.WHITE) {
visitor.discoverVertex(v);
visitor.treeEdge(u, v);
order.add(new Context<V, E>(u, edgeItr));
u = v;
edgeItr = graph.edgesOf(u).iterator();
colorMap.put(v, Color.GRAY);
} else if (color == Color.GRAY) {
visitor.backEdge(u, v);
} else {
visitor.forwardOrCrossEdge(u, v);
}
}
colorMap.put(u, Color.BLACK);
visitor.finishVertex(u);
}
}
}