/* * Copyright (c) 2008, SQL Power Group Inc. * * This file is part of SQL Power Library. * * SQL Power Library is 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. * * SQL Power Library is 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 program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.graph; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; /** * This class implements Dijkstra's algorithm. * * @param <V> The type of vertices in the graph that will be used. * @param <E> The type of edges in the graph that will be used. */ public class DijkstrasAlgorithm<V, E> { Logger logger = Logger.getLogger(DijkstrasAlgorithm.class); /** * The map of nodes to the distance between them and the starting node. Infinity is * represented by the maximum size of an int. */ private Map<V, Integer> d = new HashMap<V, Integer>(); /** * The map that contains <node, parent node> pairs when Dijkstra's algorithm is run. */ private Map<V, V> pi = new HashMap<V, V>(); /** * Performs Dijkstra's algorithm on the given graph, starting with the given * node. This algorithm is described in "Introduction to Algorithms" by * Cormen et al, Chapter 25. * * @param graph * The graph to run Dijkstra's algorithm on. * @param startingNode * The node to start running Dijkstra's algorithm from. * @return The pi map. The map contains <node, parent node> pairs given from * Dijkstra's algorithm. The map will not contain the node if it was * not reached. */ public Map<V, V> calculateShortestPaths(GraphModel<V, E> graph, V start) { initializeSingleSource(graph, start); List<V> S = new ArrayList<V>(); List<V> Q = new ArrayList<V>(graph.getNodes()); while (!Q.isEmpty()) { V u = extractMin(Q); S.add(u); for (V v: graph.getAdjacentNodes(u)) { relax(u, v); } } return pi; } /** * This method relaxes the edge between the nodes by reducing the weight of * the edges based on the shortest path from the starting node to v. * * @param u * A node that has a path to the starting node and is connected * to v. * @param v * The node that has an edge with u that we wish to relax. */ private void relax(V u, V v) { if (d.get(v) > d.get(u) + 1) { d.put(v, d.get(u) + 1); pi.put(v, u); } } /** * Extracts the node that has the shortest path to the starting node. This * node will be removed from the given list. * * @param q * The list that contains the nodes we have not reached yet in * Dijkstra's algorithm. * @return The node that has the shortest path to the starting node. */ private V extractMin(List<V> q) { V u = null; for (V v: q) { if (u == null || d.get(u) > d.get(v)) { u = v; } } q.remove(u); return u; } /** * Initializes the d and pi maps for finding the shortest paths in a graph * by using Dijkstra's algorithm. * * @param graph * The list of nodes in the graph we will be running Dijkstra's * algorithm on. * @param start * The starting node for finding the shortest path to. */ private void initializeSingleSource(GraphModel<V, E> graph, V start) { for(V v: graph.getNodes()) { d.put(v, new Integer(Integer.MAX_VALUE - 1)); } d.put(start, new Integer(0)); } }