using System; using System.Collections.Generic; using HeuristicLab.Algorithms.GraphRouting.Interfaces; using HeuristicLab.Problems.RoutePlanning.Interfaces; namespace HeuristicLab.Algorithms.GraphRouting { // simple implemntation of disjkstra's algorithm // based on: http://de.wikipedia.org/wiki/Dijkstra-Algorithmus // (doesn't use heaps ... ) public class NaiveDijkstraAlgorithm : IRouter { private IGraph graph; private HashSet visitedNodes; private HashSet unvisitedNodes; private Dictionary distances; private Dictionary predecessors; public NaiveDijkstraAlgorithm(IGraph graph) { this.graph = graph; } #region IRouter Members public long[] Calculate(long sourceNodeId, long targetNodeId) { visitedNodes = new HashSet(); // visited unvisitedNodes = new HashSet(); // unvisited distances = new Dictionary(); predecessors = new Dictionary(); List resultRoute = new List(); if (sourceNodeId == targetNodeId) { resultRoute.Add(sourceNodeId); return resultRoute.ToArray(); } long currentNode = sourceNodeId; distances.Add(currentNode, 0); unvisitedNodes.Add(currentNode); while (unvisitedNodes.Count > 0) { currentNode = GetMinimumDistance(unvisitedNodes); visitedNodes.Add(currentNode); unvisitedNodes.Remove(currentNode); if (currentNode == targetNodeId) { break; } FindMinimalWeight(currentNode); } if (currentNode != targetNodeId) { // target was not found // maybe throw exception throw new Exception(string.Format("No route found from {0} to {1}", sourceNodeId, targetNodeId)); } return GetRoute(targetNodeId).ToArray(); } #endregion public long GetNodeIdWithRank(long sourceNodeId, int rank) { visitedNodes = new HashSet(); // visited unvisitedNodes = new HashSet(); // unvisited distances = new Dictionary(); predecessors = new Dictionary(); int currentRank = 0; long currentNode = sourceNodeId; distances.Add(currentNode, 0); unvisitedNodes.Add(currentNode); while (unvisitedNodes.Count > 0) { currentNode = GetMinimumDistance(unvisitedNodes); visitedNodes.Add(currentNode); unvisitedNodes.Remove(currentNode); currentRank++; if (currentRank == rank) { break; } FindMinimalWeight(currentNode); } return currentNode; } private long GetMinimumDistance(HashSet nodeIds) { long minimum = -1; foreach (long id in nodeIds) { if (minimum == -1) minimum = id; else { if (GetDistance(id) < GetDistance(minimum)) { minimum = id; } } } return minimum; } private float GetDistance(long id) { float d; if (distances.TryGetValue(id, out d)) { return d; } else { return float.MaxValue; } } private void FindMinimalWeight(long nodeId) { Dictionary currentNeighbors = graph.GetNeighborsWithWeight(nodeId); foreach (KeyValuePair neighbor in currentNeighbors) { // update relax float totalWeight = GetDistance(nodeId) + neighbor.Value; if (GetDistance(neighbor.Key) > totalWeight) { distances[neighbor.Key] = totalWeight; predecessors[neighbor.Key] = nodeId; unvisitedNodes.Add(neighbor.Key); } } } private List GetRoute(long nodeId) { List route = new List(); long current = nodeId; long next; if (!predecessors.TryGetValue(current, out next)) { return null; } route.Add(current); while (predecessors.TryGetValue(current, out next)) { current = predecessors[current]; route.Add(current); } route.Reverse(); return route; } } }