package com.hendrix.erdos.algorithms; import com.hendrix.erdos.exceptions.AlgorithmException; import com.hendrix.erdos.graphs.IGraph; import com.hendrix.erdos.graphs.engines.IGraphEngine; import com.hendrix.erdos.types.Edge; import com.hendrix.erdos.types.IVertex; import com.hendrix.erdos.utils.SGraphUtils; import com.hendrix.erdos.graphs.AbstractGraph; import com.hendrix.erdos.algorithms.BFS.BreadthFirstTree; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Queue; import java.util.Set; /** * @author Tomer Shalev */ public class BFS extends AbstractGraphAlgorithm<BreadthFirstTree, IGraph> { protected IVertex _sourceIVertex = null; /** * The distance from the source s to IVertex u computed by the algorithm */ protected HashMap<IVertex, Integer> _D = null; /** * color state of vertices */ protected HashMap<IVertex, SGraphUtils.COLOR> _COLOR = null; /** * the predecessor of u is stored in PIE. If u has no predecessor (for example, if u = s or u has not been discovered), then π[u] = NIL */ protected LinkedHashMap<IVertex, IVertex> _PIE = null; /** * utility queue for the algorithm */ private Queue<IVertex> _Q = null; public BFS(IGraph graph_input, IVertex sourceIVertex) { super(graph_input, "Breadth First Search"); _sourceIVertex = sourceIVertex; _D = new HashMap<>(); _COLOR = new HashMap<>(); _PIE = new LinkedHashMap<>(); _Q = new LinkedList<>(); } @Override public BreadthFirstTree applyAlgorithm() { if(_sourceIVertex==null || _graph_input==null) throw new AlgorithmException("_sourceIVertex==null || _graph_input==null", this); bfs(_sourceIVertex); _result_algorithm = new BreadthFirstTree(this); _result_algorithm.setTag("BFS result"); return _result_algorithm; } @SuppressWarnings("UnusedDeclaration") public IVertex getSourceIVertex() { return _sourceIVertex; } @SuppressWarnings("UnusedDeclaration") public void setSourceIVertex(IVertex sourceIVertex) { _sourceIVertex = sourceIVertex; } @Override public void dispose() { super.dispose(); _D.clear(); _COLOR.clear(); _PIE.clear(); _Q.clear(); _sourceIVertex = null; _D = null; _COLOR = null; _PIE = null; _Q = null; } // BFS(G, s) // 1 for each IVertex u ∈ V [G] - {s} // 2 do color[u] ← WHITE // 3 d[u] ← ∞ // 4 π[u] ← NIL // 5 color[s] ← GRAY // 6 d[s] ← 0 // 7 π[s] ← NIL // 8 Q ← Ø // 9 ENQUEUE(Q, s) // 10 while Q ≠ Ø // 11 do u ← DEQUEUE(Q) // 12 for each v ∈ Adj[u] // 13 do if color[v] = WHITE // 14 then color[v] ← GRAY // 15 d[v] ← d[u] + 1 // 16 π[v] ← u // 17 ENQUEUE(Q, v) // 18 color[u] ← BLACK // private void bfs(IVertex s) { Collection<IVertex> vertices = _graph_input.vertices(); for (IVertex u : vertices) { if(u.equals(s)) continue; _COLOR.put(u, SGraphUtils.COLOR.WHITE); _D.put(u, Integer.MAX_VALUE); _PIE.put(u, null); } _COLOR.put(s, SGraphUtils.COLOR.GREY); _D.put(s, 0); _PIE.put(s, null); _Q.add(s); IVertex u; Collection<IVertex> listAdj_u; while (!_Q.isEmpty()) { u = _Q.poll(); listAdj_u = _graph_input.getNeighborsOf(u); for (IVertex v : listAdj_u) { if(_COLOR.get(v).equals(SGraphUtils.COLOR.WHITE)) { _COLOR.put(v, SGraphUtils.COLOR.GREY); _D.put(v, _D.get(u) + 1); _PIE.put(v, u); _Q.add(v); } } _COLOR.put(u, SGraphUtils.COLOR.BLACK); } } /** * the result of BFS based on the Predecessor Sub Graph, contains predecessor list, distances list * Breadth First Tree, the result of a BFS(s). represents all the * shortest paths from source IVertex to other vertices of the original graph. * * <ul> * <li/>predecessor list * <li/>starting times * <li/>edge/vertex iterations are according to the discovery order * </ul> * * @author Tomer Shalev */ public class BreadthFirstTree extends AbstractGraph { @SuppressWarnings("FieldCanBeLocal") private IVertex _sourceIVertex = null; /** * The distance from the source s to IVertex u computed by the algorithm */ private HashMap<IVertex, Integer> _D = null; /** * color state of vertices */ @SuppressWarnings("UnusedDeclaration") private HashMap<IVertex, SGraphUtils.COLOR> _COLOR = null; /** * the predecessor of u is stored in PIE. If u has no predecessor (for example, if u = s or u has not been discovered), then π[u] = NIL */ private HashMap<IVertex, IVertex> _PIE = null; /** * init the bfs tree * * @param bfs the BFS algorithm */ @SuppressWarnings("unchecked") private BreadthFirstTree(BFS bfs) { _sourceIVertex = bfs._sourceIVertex; _D = (HashMap<IVertex, Integer>)bfs._D.clone(); _PIE = (HashMap<IVertex, IVertex>)bfs._PIE.clone(); Set<IVertex> set_keys = _PIE.keySet(); IVertex parent; for (IVertex key : set_keys) { parent = _PIE.get(key); if(parent != null) { addVertex(parent); addVertex(key); addEdge(parent, key); } } addVertex(_sourceIVertex); } /** * get distance of a IVertex in this graph from the source IVertex * on which BFS was applied on. * * @param vertex the IVertex * * @return the distance */ @SuppressWarnings("UnusedDeclaration") public int getDistance(IVertex vertex) { return _D.get(vertex); } // PRINT-PATH(G, s, v) // 1 if v = s // 2 then print s // 3 else if π[v] = NIL // 4 then print "no path from" s "to" v "exists" // 5 else PRINT-PATH(G, s, π[v]) // 6 print v // /** * The following procedure prints out the vertices on a shortest path from {@code sVertex} to {@code eVertex}, * assuming that BFS has already been run to compute the shortest-path tree. * * @param sVertex from IVertex * @param eVertex to IVertex */ @SuppressWarnings("UnusedDeclaration") public void printPath(IVertex sVertex, IVertex eVertex) { if(sVertex == eVertex) printIVertex(sVertex); else if(_PIE.get(eVertex) == null) { print("no path from " + sVertex.getId() + "to" + eVertex.getId() + "exists"); } else { printPath(sVertex, _PIE.get(eVertex)); printIVertex(eVertex); } } protected void print(String msg) { System.out.print(msg); } protected void printIVertex(IVertex IVertex) { print("-" + IVertex.getId() + "-"); } @Override public Edge.EDGE_DIRECTION getGraphType() { return _graph_input.getGraphType(); } @Override public boolean hasMultiEdges() { return _graph_input.hasMultiEdges(); } @Override public boolean hasSelfLoops() { return _graph_input.hasSelfLoops(); } @Override public IGraphEngine graphEngineFactory() { return _graph_input.graphEngineFactory(); } } }