/* * Copyright (c) 2003, the JUNG Project and the Regents of the University * of California * All rights reserved. * * This software is open-source under the BSD license; see either * "license.txt" or * http://jung.sourceforge.net/license.txt for a description. */ package edu.uci.ics.jung.algorithms.shortestpath; import java.util.HashMap; import java.util.Map; import edu.uci.ics.jung.graph.Hypergraph; /** * Computes the shortest path distances for graphs whose edges are not weighted * (using BFS). * * @author Scott White */ public class UnweightedShortestPath<V, E> implements ShortestPath<V, E>, Distance<V> { private Map<V, Map<V, Number>> mDistanceMap; private Map<V, Map<V, E>> mIncomingEdgeMap; private Hypergraph<V, E> mGraph; private Map<V, Number> distances = new HashMap<V, Number>(); /** * Constructs and initializes algorithm * * @param g * the graph */ public UnweightedShortestPath(Hypergraph<V, E> g) { mDistanceMap = new HashMap<V, Map<V, Number>>(); mIncomingEdgeMap = new HashMap<V, Map<V, E>>(); mGraph = g; } /** * @see edu.uci.ics.jung.algorithms.shortestpath.Distance#getDistance(Object, * Object) */ @Override public Number getDistance(V source, V target) { Map<V, Number> sourceSPMap = getDistanceMap(source); return sourceSPMap.get(target); } /** * @see edu.uci.ics.jung.algorithms.shortestpath.Distance#getDistanceMap(Object) */ @Override public Map<V, Number> getDistanceMap(V source) { Map<V, Number> sourceSPMap = mDistanceMap.get(source); if (sourceSPMap == null) { computeShortestPathsFromSource(source); sourceSPMap = mDistanceMap.get(source); } return sourceSPMap; } /** * @see edu.uci.ics.jung.algorithms.shortestpath.ShortestPath#getIncomingEdgeMap(Object) */ @Override public Map<V, E> getIncomingEdgeMap(V source) { Map<V, E> sourceIEMap = mIncomingEdgeMap.get(source); if (sourceIEMap == null) { computeShortestPathsFromSource(source); sourceIEMap = mIncomingEdgeMap.get(source); } return sourceIEMap; } /** * Computes the shortest path distances from a given node to all other * nodes. * * @param source * the source node */ private void computeShortestPathsFromSource(V source) { BFSDistanceLabeler<V, E> labeler = new BFSDistanceLabeler<V, E>(); labeler.labelDistances(mGraph, source); distances = labeler.getDistanceDecorator(); Map<V, Number> currentSourceSPMap = new HashMap<V, Number>(); Map<V, E> currentSourceEdgeMap = new HashMap<V, E>(); for (V vertex : mGraph.getVertices()) { Number distanceVal = distances.get(vertex); // BFSDistanceLabeler uses -1 to indicate unreachable vertices; // don't bother to store unreachable vertices if (distanceVal != null && distanceVal.intValue() >= 0) { currentSourceSPMap.put(vertex, distanceVal); int minDistance = distanceVal.intValue(); for (E incomingEdge : mGraph.getInEdges(vertex)) { for (V neighbor : mGraph .getIncidentVertices(incomingEdge)) { if (neighbor.equals(vertex)) { continue; // V neighbor = mGraph.getOpposite(vertex, // incomingEdge); } Number predDistanceVal = distances.get(neighbor); int pred_distance = predDistanceVal.intValue(); if (pred_distance < minDistance && pred_distance >= 0) { minDistance = predDistanceVal.intValue(); currentSourceEdgeMap.put(vertex, incomingEdge); } } } } } mDistanceMap.put(source, currentSourceSPMap); mIncomingEdgeMap.put(source, currentSourceEdgeMap); } /** * Clears all stored distances for this instance. Should be called whenever * the graph is modified (edge weights changed or edges added/removed). If * the user knows that some currently calculated distances are unaffected by * a change, <code>reset(V)</code> may be appropriate instead. * * @see #reset(Object) */ public void reset() { mDistanceMap.clear(); mIncomingEdgeMap.clear(); } /** * Clears all stored distances for the specified source vertex * <code>source</code>. Should be called whenever the stored distances from * this vertex are invalidated by changes to the graph. * * @see #reset() */ public void reset(V v) { mDistanceMap.remove(v); mIncomingEdgeMap.remove(v); } }