/** * This file is part of Relation Analyzer for OSM. * Copyright (c) 2001 by Adrian Stabiszewski, as@grundid.de * * Relation Analyzer is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Relation Analyzer 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Relation Analyzer. If not, see <http://www.gnu.org/licenses/>. */ package org.osmtools.ra.dijkstra; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; public class Dijkstra { private final Iterable<? extends Edge> edges; private Set<Vertex> settledNodes; private Set<Vertex> unSettledNodes; private Map<Vertex, Vertex> predecessors; private Map<Vertex, Integer> distance; public Dijkstra(Iterable<? extends Edge> edges) { this.edges = edges; } public void execute(Vertex source) { init(); distance.put(source, 0); unSettledNodes.add(source); while (unSettledNodes.size() > 0) { Vertex node = getMinimum(unSettledNodes); settledNodes.add(node); unSettledNodes.remove(node); findMinimalDistances(node); } } private void init() { settledNodes = new HashSet<Vertex>(); unSettledNodes = new HashSet<Vertex>(); distance = new HashMap<Vertex, Integer>(); predecessors = new HashMap<Vertex, Vertex>(); } private void findMinimalDistances(Vertex node) { List<Vertex> adjacentNodes = getNeighbors(node); for (Vertex target : adjacentNodes) { if (getShortestDistance(target) > getShortestDistance(node) + getDistance(node, target)) { distance.put(target, getShortestDistance(node) + getDistance(node, target)); predecessors.put(target, node); unSettledNodes.add(target); } } } private int getDistance(Vertex node, Vertex target) { for (Edge edge : edges) { if (edge.getSource().equals(node) && edge.getDestination().equals(target)) { return edge.getWeight(); } } throw new RuntimeException("Should not happen"); } private List<Vertex> getNeighbors(Vertex node) { List<Vertex> neighbors = new ArrayList<Vertex>(); for (Edge edge : edges) { if (edge.getSource().equals(node) && !isSettled(edge.getDestination())) { neighbors.add(edge.getDestination()); } } return neighbors; } private Vertex getMinimum(Set<Vertex> vertexes) { Vertex minimum = null; for (Vertex vertex : vertexes) { if (minimum == null) { minimum = vertex; } else { if (getShortestDistance(vertex) < getShortestDistance(minimum)) { minimum = vertex; } } } return minimum; } private boolean isSettled(Vertex vertex) { return settledNodes.contains(vertex); } private int getShortestDistance(Vertex destination) { Integer d = distance.get(destination); if (d == null) { return Integer.MAX_VALUE; } else { return d.intValue(); } } /** * This method returns the path from the source to the selected target. An empty list is returned if no path is * found. */ public List<Vertex> getPath(Vertex target) { if (predecessors.containsKey(target)) { LinkedList<Vertex> path = new LinkedList<Vertex>(); do { path.add(target); target = predecessors.get(target); } while (target != null); Collections.reverse(path); return path; } else return Collections.emptyList(); } }