Dijkstra's algorithm: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 1,233: Line 1,233:


=={{header|Ruby}}==
=={{header|Ruby}}==
This solution is incorrect. Since the path is directed and f is only a sink, f cannot be in the middle of a path.

{{works with|Ruby|1.9.2+}} (for INFINITY)
{{works with|Ruby|1.9.2+}} (for INFINITY)
Notes for this solution:
Notes for this solution:

Revision as of 04:04, 21 December 2012

Dijkstra's algorithm is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
This page uses content from Wikipedia. The original article was at Dijkstra's algorithm. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)

Dijkstra's algorithm, conceived by Dutch computer scientist Edsger Dijkstra in 1956 and published in 1959, is a graph search algorithm that solves the single-source shortest path problem for a graph with nonnegative edge path costs, producing a shortest path tree. This algorithm is often used in routing and as a subroutine in other graph algorithms.

For a given source vertex (node) in the graph, the algorithm finds the path with lowest cost (i.e. the shortest path) between that vertex and every other vertex. It can also be used for finding costs of shortest paths from a single vertex to a single destination vertex by stopping the algorithm once the shortest path to the destination vertex has been determined. For example, if the vertices of the graph represent cities and edge path costs represent driving distances between pairs of cities connected by a direct road, Dijkstra's algorithm can be used to find the shortest route between one city and all other cities. As a result, the shortest path first is widely used in network routing protocols, most notably IS-IS and OSPF (Open Shortest Path First).

Task:

  1. Implement a version of Dijkstra's algorithm that computes a shortest path from a start vertex to an end vertex in a directed graph.
  2. Run your program with the following directed graph to find the shortest path from vertex "a" to vertex "e."
  3. Show the output of your program.
Vertices
Number Name
1 a
2 b
3 c
4 d
5 e
6 f
Edges
Start End Cost
a b 7
a c 9
a f 14
b c 10
b d 15
c d 11
c f 2
d e 6
e f 9

You can use numbers or names to identify vertices in your program.

Extra Credit: Document the specific algorithm implemented. The {{trans}} template is sufficient. Otherwise add text outside of your program or add comments within your program. This is not a requirement to explain how the algorithm works, but to state which algorithm is implemented. If your code follows an external source such as the Wikipedia pseudocode, you can state that. You can state if it is Dijkstra's original algorithm or some more efficient variant. It is relevant to mention things like priority queues, heaps, and expected time complexity in big-O notation. If a priority queue is used, it is important to discuss how the step of decreasing the distance of a node is accomplished, and whether it is linear or logarithmic time.

C

Standard binary heap-as-priority queue affair. Only that each node links back to its heap position for easier update.

There are two main() functions to choose from (look for #define BIG_EXAMPLE), one is for task example, the other is a much heavier duty test case. <lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <string.h>

//#define BIG_EXAMPLE

typedef struct node_t node_t, *heap_t; typedef struct edge_t edge_t; struct edge_t { node_t *nd; /* target of this edge */ edge_t *sibling;/* for singly linked list */ int len; /* edge cost */ }; struct node_t { edge_t *edge; /* singly linked list of edges */ node_t *via; /* where previous node is in shortest path */ double dist; /* distance from origining node */ char name[8]; /* the, er, name */ int heap_idx; /* link to heap position for updating distance */ };


/* --- edge management --- */

  1. ifdef BIG_EXAMPLE
  2. define BLOCK_SIZE (1024 * 32 - 1)
  3. else
  4. define BLOCK_SIZE 15
  5. endif

edge_t *edge_root = 0, *e_next = 0;

/* Don't mind the memory management stuff, they are besides the point.

  Pretend e_next = malloc(sizeof(edge_t)) */

void add_edge(node_t *a, node_t *b, double d) { if (e_next == edge_root) { edge_root = malloc(sizeof(edge_t) * (BLOCK_SIZE + 1)); edge_root[BLOCK_SIZE].sibling = e_next; e_next = edge_root + BLOCK_SIZE; } --e_next;

e_next->nd = b; e_next->len = d; e_next->sibling = a->edge; a->edge = e_next; }

void free_edges() { for (; edge_root; edge_root = e_next) { e_next = edge_root[BLOCK_SIZE].sibling; free(edge_root); } }

/* --- priority queue stuff --- */ heap_t *heap; int heap_len;

void set_dist(node_t *nd, node_t *via, double d) { int i, j;

/* already knew better path */ if (nd->via && d >= nd->dist) return;

/* find existing heap entry, or create a new one */ nd->dist = d; nd->via = via;

i = nd->heap_idx; if (!i) i = ++heap_len;

/* upheap */ for (; i > 1 && nd->dist < heap[j = i/2]->dist; i = j) (heap[i] = heap[j])->heap_idx = i;

heap[i] = nd; nd->heap_idx = i; }

node_t * pop_queue() { node_t *nd, *tmp; int i, j;

if (!heap_len) return 0;

/* remove leading element, pull tail element there and downheap */ nd = heap[1]; tmp = heap[heap_len--];

for (i = 1; i < heap_len && (j = i * 2) <= heap_len; i = j) { if (j < heap_len && heap[j]->dist > heap[j+1]->dist) j++;

if (heap[j]->dist >= tmp->dist) break; (heap[i] = heap[j])->heap_idx = i; }

heap[i] = tmp; tmp->heap_idx = i;

return nd; }

/* --- Dijkstra stuff; unreachable nodes will never make into the queue --- */ void calc_all(node_t *start) { node_t *lead; edge_t *e;

set_dist(start, start, 0); while ((lead = pop_queue())) for (e = lead->edge; e; e = e->sibling) set_dist(e->nd, lead, lead->dist + e->len); }

void show_path(node_t *nd) { if (nd->via == nd) printf("%s", nd->name); else if (!nd->via) printf("%s(unreached)", nd->name); else { show_path(nd->via); printf("-> %s(%g) ", nd->name, nd->dist); } }

int main(void) {

  1. ifndef BIG_EXAMPLE

int i;

  1. define N_NODES ('f' - 'a' + 1)

node_t *nodes = calloc(sizeof(node_t), N_NODES);

for (i = 0; i < N_NODES; i++) sprintf(nodes[i].name, "%c", 'a' + i);

  1. define E(a, b, c) add_edge(nodes + (a - 'a'), nodes + (b - 'a'), c)

E('a', 'b', 7); E('a', 'c', 9); E('a', 'f', 14); E('b', 'c', 10);E('b', 'd', 15);E('c', 'd', 11); E('c', 'f', 2); E('d', 'e', 6); E('e', 'f', 9);

  1. undef E
  1. else /* BIG_EXAMPLE */

int i, j, c;

  1. define N_NODES 4000

node_t *nodes = calloc(sizeof(node_t), N_NODES);

for (i = 0; i < N_NODES; i++) sprintf(nodes[i].name, "%d", i + 1);

/* given any pair of nodes, there's about 50% chance they are not connected; if connected, the cost is randomly chosen between 0 and 49 (inclusive! see output for consequences) */ for (i = 0; i < N_NODES; i++) { for (j = 0; j < N_NODES; j++) { /* majority of runtime is actually spent here */ if (i == j) continue; c = rand() % 100; if (c < 50) continue; add_edge(nodes + i, nodes + j, c - 50); } }

  1. endif

heap = calloc(sizeof(heap_t), N_NODES + 1); heap_len = 0;

calc_all(nodes); for (i = 0; i < N_NODES; i++) { show_path(nodes + i); putchar('\n'); }

  1. if 0

/* real programmers don't free memories (they use Fortran) */ free_edges(); free(heap); free(nodes);

  1. endif

return 0;

}</lang>output

a
a-> b(7) 
a-> c(9) 
a-> c(9) -> d(20) 
a-> c(9) -> d(20) -> e(26) 
a-> c(9) -> f(11)

C++

(Modified from LiteratePrograms, which is MIT/X11 licensed.)

Solution follows Dijkstra's algorithm as described elsewhere. Data like min-distance, previous node, neighbors, are kept in separate data structures instead of part of the vertex. We number the vertexes starting from 0, and represent the graph using an adjacency list (vector whose i'th element is the vector of neighbors that vertex i has edges to) for simplicity.

For the priority queue of vertexes, we use a self-balancing binary search tree (std::set), which should bound time complexity by O(E log V). Although C++ has heaps, without knowing the index of an element it would take linear time to find it to re-order it for a changed weight. It is not easy to keep the index of vertexes in the heap because the heap operations are opaque without callbacks. On the other hand, using a self-balancing binary search tree is efficient because it has the same log(n) complexity for insertion and removal of the head element as a binary heap. In addition, a self-balancing binary search tree also allows us to find and remove any other element in log(n) time, allowing us to perform the decrease-key step in logarithmic time by removing and re-inserting.

We do not need to keep track of whether a vertex is "done" ("visited") as in the Wikipedia description, since re-reaching such a vertex will always fail the relaxation condition (when re-reaching a "done" vertex, the new distance will never be less than it was originally), so it will be skipped anyway.

<lang cpp>#include <iostream>

  1. include <vector>
  2. include <string>
  3. include <list>
  1. include <limits> // for numeric_limits
  1. include <set>
  2. include <utility> // for pair
  3. include <algorithm>
  4. include <iterator>


typedef int vertex_t; typedef double weight_t;

const weight_t max_weight = std::numeric_limits<double>::infinity();

struct neighbor {

   vertex_t target;
   weight_t weight;
   neighbor(vertex_t arg_target, weight_t arg_weight)
       : target(arg_target), weight(arg_weight) { }

};

typedef std::vector<std::vector<neighbor> > adjacency_list_t;


void DijkstraComputePaths(vertex_t source,

                         const adjacency_list_t &adjacency_list,
                         std::vector<weight_t> &min_distance,
                         std::vector<vertex_t> &previous)

{

   int n = adjacency_list.size();
   min_distance.clear();
   min_distance.resize(n, max_weight);
   min_distance[source] = 0;
   previous.clear();
   previous.resize(n, -1);
   std::set<std::pair<weight_t, vertex_t> > vertex_queue;
   vertex_queue.insert(std::make_pair(min_distance[source], source));
   while (!vertex_queue.empty()) 
   {
       weight_t dist = vertex_queue.begin()->first;
       vertex_t u = vertex_queue.begin()->second;
       vertex_queue.erase(vertex_queue.begin());
       // Visit each edge exiting u

const std::vector<neighbor> &neighbors = adjacency_list[u];

       for (std::vector<neighbor>::const_iterator neighbor_iter = neighbors.begin();
            neighbor_iter != neighbors.end();
            neighbor_iter++)
       {
           vertex_t v = neighbor_iter->target;
           weight_t weight = neighbor_iter->weight;
           weight_t distance_through_u = dist + weight;

if (distance_through_u < min_distance[v]) { vertex_queue.erase(std::make_pair(min_distance[v], v));

min_distance[v] = distance_through_u; previous[v] = u; vertex_queue.insert(std::make_pair(min_distance[v], v));

}

       }
   }

}


std::list<vertex_t> DijkstraGetShortestPathTo(

   vertex_t vertex, const std::vector<vertex_t> &previous)

{

   std::list<vertex_t> path;
   for ( ; vertex != -1; vertex = previous[vertex])
       path.push_front(vertex);
   return path;

}


int main() {

   // remember to insert edges both ways for an undirected graph
   adjacency_list_t adjacency_list(6);
   // 0 = a
   adjacency_list[0].push_back(neighbor(1, 7));
   adjacency_list[0].push_back(neighbor(2, 9));
   adjacency_list[0].push_back(neighbor(5, 14));
   // 1 = b
   adjacency_list[1].push_back(neighbor(0, 7));
   adjacency_list[1].push_back(neighbor(2, 10));
   adjacency_list[1].push_back(neighbor(3, 15));
   // 2 = c
   adjacency_list[2].push_back(neighbor(0, 9));
   adjacency_list[2].push_back(neighbor(1, 10));
   adjacency_list[2].push_back(neighbor(3, 11));
   adjacency_list[2].push_back(neighbor(5, 2));
   // 3 = d
   adjacency_list[3].push_back(neighbor(1, 15));
   adjacency_list[3].push_back(neighbor(2, 11));
   adjacency_list[3].push_back(neighbor(4, 6));
   // 4 = e
   adjacency_list[4].push_back(neighbor(3, 6));
   adjacency_list[4].push_back(neighbor(5, 9));
   // 5 = f
   adjacency_list[5].push_back(neighbor(0, 14));
   adjacency_list[5].push_back(neighbor(2, 2));
   adjacency_list[5].push_back(neighbor(4, 9));
   std::vector<weight_t> min_distance;
   std::vector<vertex_t> previous;
   DijkstraComputePaths(0, adjacency_list, min_distance, previous);
   std::cout << "Distance from 0 to 4: " << min_distance[4] << std::endl;
   std::list<vertex_t> path = DijkstraGetShortestPathTo(4, previous);
   std::cout << "Path : ";
   std::copy(path.begin(), path.end(), std::ostream_iterator<vertex_t>(std::cout, " "));
   std::cout << std::endl;
   return 0;

}</lang>

D

This solution is incorrect. Since the path is directed and f is only a sink, f cannot be in the middle of a path.

Translation of: C++

The algorithm and the important data structures are essentially the same as in the C++ version, so the same comments apply (built-in D associative arrays are unsorted). <lang d>import std.stdio, std.typecons, std.algorithm, std.container;

alias string Vertex; alias int Weight;

const struct Neighbor {

   Vertex target;
   Weight weight;

}

alias Neighbor[][Vertex] AdjacencyMap;

Tuple!(Weight[Vertex], Vertex[Vertex]) dijkstraComputePaths(in Vertex source,

                    in Vertex target,
                    in AdjacencyMap adjacencyMap) /*pure nothrow*/ {
   typeof(typeof(return)[0]) minDistance;
   foreach (v, neighs; adjacencyMap) {
       minDistance[v] = Weight.max;
       foreach (n; neighs)
           minDistance[n.target] = Weight.max;
   }
   minDistance[source] = 0;
   alias Tuple!(Weight, Vertex) Pair;
   auto vertexQueue = redBlackTree(Pair(minDistance[source], source));
   typeof(typeof(return)[1]) previous;
   while (!vertexQueue.empty) {
       const u = vertexQueue.front()[1];
       vertexQueue.removeFront();
       if (u == target)
           break;
       // Visit each edge exiting u
       foreach (n; adjacencyMap[u]) {
           const v = n.target;
           const distanceThroughU = minDistance[u] + n.weight;
           if (distanceThroughU < minDistance[v]) {
               vertexQueue.removeKey(Pair(minDistance[v], v));
               minDistance[v] = distanceThroughU;
               previous[v] = u;
               vertexQueue.insert(Pair(minDistance[v], v));
           }
       }
   }
   return tuple(minDistance, previous);

}

Vertex[] dijkstraGetShortestPathTo(Vertex v,

                                  in Vertex[Vertex] previous)

pure nothrow {

   auto path = [v];
   while (v in previous) {
       v = previous[v];
       if (v == path[$ - 1])
           break;
       path ~= v;
   }
   path.reverse();
   return path;

}

void main() {

   AdjacencyMap adj;
   immutable arcs = [tuple("a", "b", 7),
                     tuple("a", "c", 9),
                     tuple("a", "f", 14),
                     tuple("b", "c", 10),
                     tuple("b", "d", 15),
                     tuple("c", "d", 11),
                     tuple("c", "f", 2),
                     tuple("d", "e", 6),
                     tuple("e", "f", 9)];
   foreach (arc; arcs) {
       // Edges in both directions for an undirected graph
       adj[arc[0]] ~= Neighbor(arc[1], arc[2]);
       adj[arc[1]] ~= Neighbor(arc[0], arc[2]);
   }
   const minDist_prev = dijkstraComputePaths("a", "e", adj);
   const minDistance = minDist_prev[0];
   const previous = minDist_prev[1];
   writeln("Distance from a to e: ", minDistance["e"]);
   writeln("Path : ", dijkstraGetShortestPathTo("e", previous));

}</lang>

Output:
Distance from a to e: 20
Path : ["a", "c", "f", "e"]

Go

Algorithm is derived from Wikipedia section 1, titled "Algorithm," with nodes stored in a heap, which should bound time complexity by O(E log V). Decreasing the distance of a node is accomplished by removing it from the heap and then re-inserting it. Linear-time traversal to find the node in the heap is avoided by keeping the index of each node in the heap as a field of the node, and our heap operations ensure that this variable is updated appropriately whenever nodes are moved in the heap. Thus removal from the heap is accomplished in logarithmic time.

Comments in the code below refer to corresponding steps in that section of the WP page. A significant variation in step 2 is that the unvisited set is not initially populated. Instead, the unvisited set is maintained as the "tentative" set, as illustrated on the WP page in the animated image showing robot motion planning.

The heap support comes from the Go standard library. The three operations used here are each documented to have O(log n) complexity. <lang go>package main

import (

   "container/heap"
   "fmt"
   "math"

)

// edge struct holds the bare data needed to define a graph. type edge struct {

   vert1, vert2 string
   dist         int

}

func main() {

   // example data and parameters
   graph := []edge{
       {"a", "b", 7},
       {"a", "c", 9},
       {"a", "f", 14},
       {"b", "c", 10},
       {"b", "d", 15},
       {"c", "d", 11},
       {"c", "f", 2},
       {"d", "e", 6},
       {"e", "f", 9},
   }
   directed := true
   start := "a"
   end := "e"
   findAll := false
   // construct linked representation of example data
   allNodes, startNode, endNode := linkGraph(graph, directed, start, end)
   if directed {
       fmt.Print("Directed")
   } else {
       fmt.Print("Undirected")
   }
   fmt.Printf(" graph with %d nodes, %d edges\n", len(allNodes), len(graph))
   if startNode == nil {
       fmt.Printf("start node %q not found in graph\n", start)
       return
   }
   if findAll {
       endNode = nil
   } else if endNode == nil {
       fmt.Printf("end node %q not found in graph\n", end)
       return
   }
   // run Dijkstra's shortest path algorithm
   paths := dijkstra(allNodes, startNode, endNode)
   fmt.Println("Shortest path(s):")
   for _, p := range paths {
       fmt.Println(p.path, "length", p.length)
   }

}

// node and neighbor structs hold data useful for the heap-optimized // Dijkstra's shortest path algorithm type node struct {

   vert string     // vertex name
   tent int        // tentative distance
   prev *node      // previous node in shortest path back to start
   done bool       // true when tent and prev represent shortest path
   nbs  []neighbor // edges from this vertex
   rx   int        // heap.Remove index

}

type neighbor struct {

   nd   *node // node corresponding to vertex
   dist int   // distance to this node (from whatever node references this)

}

// linkGraph constructs a linked representation of the input graph, // with additional fields needed by the shortest path algorithm. // // Return value allNodes will contain all nodes found in the input graph, // even ones not reachable from the start node. // Return values startNode, endNode will be nil if the specified start or // end node names are not found in the graph. func linkGraph(graph []edge, directed bool,

   start, end string) (allNodes []*node, startNode, endNode *node) {
   all := make(map[string]*node)
   // one pass over graph to collect nodes
   for _, e := range graph {
       if all[e.vert1] == nil {
           all[e.vert1] = &node{vert: e.vert1}
       }
       if all[e.vert2] == nil {
           all[e.vert2] = &node{vert: e.vert2}
       }
   }
   // second pass to link neighbors
   for _, e := range graph {
       n1 := all[e.vert1]
       n2 := all[e.vert2]
       n1.nbs = append(n1.nbs, neighbor{n2, e.dist})
       if !directed {
           n2.nbs = append(n2.nbs, neighbor{n1, e.dist})
       } 
   }
   allNodes = make([]*node, len(all))
   var n int
   for _, nd := range all {
       allNodes[n] = nd
       n++
   }
   return allNodes, all[start], all[end]

}

// return type type path struct {

   path   []string
   length int

}

const maxInt = math.MaxInt32

// dijkstra is a heap-enhanced version of Dijkstra's shortest path algorithm. // // If endNode is specified, only a single path is returned. // If endNode is nil, paths to all nodes are returned. // // Note input allNodes is needed to efficiently accomplish WP steps 1 and 2. // This initialization could be done in linkGraph, but is done here to more // closely follow the WP algorithm. func dijkstra(allNodes []*node, startNode, endNode *node) (pl []path) {

   // WP steps 1 and 2.
   for _, nd := range allNodes {
       nd.tent = maxInt
       nd.done = false
       nd.prev = nil
   }
   current := startNode
   current.tent = 0
   var unvis ndList
   for {
       // WP step 3: update tentative distances to neighbors
       for _, nb := range current.nbs {
           if nd := nb.nd; !nd.done {
               if d := current.tent + nb.dist; d < nd.tent {
                   if nd.prev != nil {
                       heap.Remove(&unvis, nd.rx)
                   }
                   nd.tent = d
                   nd.prev = current
                   heap.Push(&unvis, nd)
               }
           }
       }
       // WP step 4: mark current node visited, record path and distance
       current.done = true
       if endNode == nil || current == endNode {
           // record path and distance for return value
           distance := current.tent
           // recover path by tracing prev links,
           var p []string
           for {
               p = append(p, current.vert)
               current = current.prev
               if current == nil {
                   break
               }
           }
           // then reverse list
           for i := (len(p) + 1) / 2; i > 0; i-- {
               p[i-1], p[len(p)-i] = p[len(p)-i], p[i-1]
           }
           pl = append(pl, path{p, distance}) // pl is return value
           // WP step 5 (case of end node reached)
           if endNode != nil {
               return
           }
       }
       if len(unvis) == 0 {
           break // WP step 5 (case of no more reachable nodes)
       }
       // WP step 6: new current is node with smallest tentative distance
       current = heap.Pop(&unvis).(*node)
   }
   return

}

// ndList implements container/heap type ndList []*node

func (n ndList) Len() int { return len(n) } func (n ndList) Less(i, j int) bool { return n[i].tent < n[j].tent } func (n ndList) Swap(i, j int) {

   n[i], n[j] = n[j], n[i]
   n[i].rx = i
   n[j].rx = j

} func (n *ndList) Push(x interface{}) {

   nd := x.(*node)
   nd.rx = len(*n)
   *n = append(*n, nd)

} func (n *ndList) Pop() interface{} {

   s := *n
   if len(s) == 0 {
       return nil
   }
   last := len(s) - 1
   r := s[last]
   *n = s[:last]
   return r

}</lang>

Output:
Directed graph with 6 nodes, 9 edges
Shortest path(s):
[a c d e] length 26

Haskell

Translation of: C++

Translation of the C++ solution, and all the complexities are the same as in the C++ solution. In particular, we again use a self-balancing binary search tree (Data.Set) to implement the priority queue, which results in an optimal complexity. <lang haskell>import Data.Array import Data.Array.MArray import Data.Array.ST import Control.Monad.ST import Control.Monad (foldM) import Data.Set as S

dijkstra :: (Ix v, Num w, Ord w, Bounded w) => v -> v -> Array v [(v,w)] -> (Array v w, Array v v) dijkstra src invalid_index adj_list = runST $ do

 min_distance <- newSTArray b maxBound
 writeArray min_distance src 0
 previous <- newSTArray b invalid_index
 let aux vertex_queue =
       case S.minView vertex_queue of
         Nothing -> return ()
         Just ((dist, u), vertex_queue') ->
           let edges = adj_list ! u
               f vertex_queue (v, weight) = do
                 let dist_thru_u = dist + weight
                 old_dist <- readArray min_distance v
                 if dist_thru_u >= old_dist then
                   return vertex_queue
                 else do
                   let vertex_queue' = S.delete (old_dist, v) vertex_queue
                   writeArray min_distance v dist_thru_u
                   writeArray previous v u
                   return $ S.insert (dist_thru_u, v) vertex_queue'
           in
           foldM f vertex_queue' edges >>= aux
 aux (S.singleton (0, src))
 m <- freeze min_distance
 p <- freeze previous
 return (m, p)
 where b = bounds adj_list
       newSTArray :: Ix i => (i,i) -> e -> ST s (STArray s i e)
       newSTArray = newArray

shortest_path_to :: (Ix v) => v -> v -> Array v v -> [v] shortest_path_to target invalid_index previous =

 aux target [] where
   aux vertex acc | vertex == invalid_index = acc
                  | otherwise = aux (previous ! vertex) (vertex : acc)

adj_list :: Array Char [(Char, Int)] adj_list = listArray ('a', 'f') [ [('b',7), ('c',9), ('f',14)],

                                 [('a',7), ('c',10), ('d',15)],
                                 [('a',9), ('b',10), ('d',11), ('f',2)],
                                 [('b',15), ('c',11), ('e',6)],
                                 [('d',6), ('f',9)],
                                 [('a',14), ('c',2), ('e',9)] ]

main :: IO () main = do

 let (min_distance, previous) = dijkstra 'a' ' ' adj_list
 putStrLn $ "Distance from a to e: " ++ show (min_distance ! 'e')
 let path = shortest_path_to 'e' ' ' previous
 putStrLn $ "Path: " ++ show path</lang>

Java

Notes for this solution:

  • The number of nodes is fixed to less than 50
  • At every iteration, the next minimum distance node found by linear traversal of all nodes, which is inefficient.

<lang java>import java.io.*; import java.util.*;

class Graph {

   private static final int MAXNODES = 50;
   private static final int INFINITY = Integer.MAX_VALUE;
   int n;
   int[][] weight = new int[MAXNODES][MAXNODES];
   int[] distance = new int[MAXNODES];
   int[] precede = new int[MAXNODES];
   /**
    * Find the shortest path across the graph using Dijkstra's algorithm.
    */
   void buildSpanningTree(int source, int destination) {

boolean[] visit = new boolean[MAXNODES];

for (int i=0 ; i<n ; i++) { distance[i] = INFINITY; precede[i] = INFINITY; } distance[source] = 0;

int current = source; while (current != destination) { int distcurr = distance[current]; int smalldist = INFINITY; int k = -1; visit[current] = true;

for (int i=0; i<n; i++) { if (visit[i]) continue;

int newdist = distcurr + weight[current][i]; if (newdist < distance[i]) { distance[i] = newdist; precede[i] = current; } if (distance[i] < smalldist) { smalldist = distance[i]; k = i; } } current = k; }

   }
   /**
    * Get the shortest path across a tree that has had its path weights
    * calculated.
    */
   int[] getShortestPath(int source, int destination) {

int i = destination; int finall = 0; int[] path = new int[MAXNODES];

path[finall] = destination; finall++; while (precede[i] != source) { i = precede[i]; path[finall] = i; finall++; } path[finall] = source;

int[] result = new int[finall+1]; System.arraycopy(path, 0, result, 0, finall+1); return result;

   }
   /**
    * Print the result.
    */
   void displayResult(int[] path) {

System.out.println("\nThe shortest path followed is : \n"); for (int i = path.length-1 ; i>0 ; i--) System.out.println("\t\t( " + path[i] + " ->" + path[i-1] + " ) with cost = " + weight[path[i]][path[i-1]]); System.out.println("For the Total Cost = " + distance[path[path.length-1]]);

   }
   /**
    * Prompt for a number.
    */
   int getNumber(String msg) {

int ne = 0; BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

try { System.out.print("\n" + msg + " : "); ne = Integer.parseInt(in.readLine()); } catch (Exception e) { System.out.println("I/O Error"); } return ne;

   }
   /**
    * Prompt for a tree, build and display a path across it.
    */
   void SPA() {

n = getNumber("Enter the number of nodes (Less than " + MAXNODES + ") in the matrix");

System.out.print("\nEnter the cost matrix : \n\n"); for (int i=0 ; i<n ; i++) for (int j=0 ; j<n ; j++) weight[i][j] = getNumber("Cost " + (i+1) + "--" + (j+1));

int s = getNumber("Enter the source node"); int d = getNumber("Enter the destination node");

buildSpanningTree(s, d); displayResult(getShortestPath(s, d));

   }

}

public class Dijkstra {

   public static void main(String args[]) {

Graph g = new Graph(); g.SPA();

   }

}</lang>

Mathematica

This is beautiful, but incorrect. This solution is incorrect. Since the path is directed and f is only a sink, f cannot be in the middle of a path.

<lang Mathematica>bd = Graph[ { "a"\[UndirectedEdge] "b", "a"\[UndirectedEdge] "c", "b"\[UndirectedEdge] "c", "b"\[UndirectedEdge] "d", "c"\[UndirectedEdge] "d", "d"\[UndirectedEdge] "e", "a"\[UndirectedEdge] "f", "c"\[UndirectedEdge] "f", "e"\[UndirectedEdge] "f" } , EdgeWeight->{7,9,10,15,11,6,14,2,9},VertexLabels->"Name", VertexLabelStyle->Directive[Black,20],ImagePadding->20]

FindShortestPath[bd, "a", "e", Method -> "Dijkstra"] -> {"a", "c", "f", "e"}</lang>

Maxima

<lang maxima>load(graphs)$ g: create_graph([[1, "a"], [2, "b"], [3, "c"], [4, "d"], [5, "e"], [6, "f"]],

  [[[1, 2], 7],
   [[1, 3], 9],
   [[1, 6], 14],
   [[2, 3], 10],
   [[2, 4], 15],
   [[3, 4], 11],
   [[3, 6], 2],
   [[4, 5], 6],
   [[5, 6], 9]], directed)$
   

shortest_weighted_path(1, 5, g); /* [26, [1, 3, 4, 5]] */</lang>

OCaml

Just a straightforward implementation of the pseudo-code from the Wikipedia article:

<lang ocaml>let list_vertices graph =

 List.fold_left (fun acc ((a, b), _) ->
   let acc = if List.mem b acc then acc else b::acc in
   let acc = if List.mem a acc then acc else a::acc in
   acc
 ) [] graph

let neighbors v =

 List.fold_left (fun acc ((a, b), d) ->
   if a = v then (b, d)::acc else acc
 ) []

let remove_from v lst =

 let rec aux acc = function [] -> failwith "remove_from"
 | x::xs -> if x = v then List.rev_append acc xs else aux (x::acc) xs
 in aux [] lst

let with_smallest_distance q dist =

 match q with
 | [] -> assert false
 | x::xs ->
     let rec aux distance v = function
     | x::xs ->
         let d = Hashtbl.find dist x in
         if d < distance
         then aux d x xs
         else aux distance v xs
     | [] -> (v, distance)
     in
     aux (Hashtbl.find dist x) x xs

let dijkstra max_val zero add graph source target =

 let vertices = list_vertices graph in
 let dist_between u v =
   try List.assoc (u, v) graph
   with _ -> zero
 in
 let dist = Hashtbl.create 1 in
 let previous = Hashtbl.create 1 in
 List.iter (fun v ->                  (* initializations *)
   Hashtbl.add dist v max_val         (* unknown distance function from source to v *)
 ) vertices;
 Hashtbl.replace dist source zero;    (* distance from source to source *)
 let rec loop = function [] -> ()
 | q ->
     let u, dist_u =
       with_smallest_distance q dist in   (* vertex in q with smallest distance in dist *)
     if dist_u = max_val then
       failwith "vertices inaccessible";  (* all remaining vertices are inaccessible from source *)
     if u = target then () else begin
       let q = remove_from u q in
       List.iter (fun (v, d) ->
         if List.mem v q then begin
           let alt = add dist_u (dist_between u v) in
           let dist_v = Hashtbl.find dist v in
           if alt < dist_v then begin       (* relax (u,v,a) *)
             Hashtbl.replace dist v alt;
             Hashtbl.replace previous v u;  (* previous node in optimal path from source *)
           end
         end
       ) (neighbors u graph);
       loop q
     end
 in
 loop vertices;
 let s = ref [] in
 let u = ref target in
 while Hashtbl.mem previous !u do
   s := !u :: !s;
   u := Hashtbl.find previous !u
 done;
 (source :: !s)

let () =

 let graph =
   [ ("a", "b"), 7;
     ("a", "c"), 9;
     ("a", "f"), 14;
     ("b", "c"), 10;
     ("b", "d"), 15;
     ("c", "d"), 11;
     ("c", "f"), 2;
     ("d", "e"), 6;
     ("e", "f"), 9; ]
 in
 let p = dijkstra max_int 0 (+) graph "a" "e" in
 print_endline (String.concat " -> " p)</lang>

Output:

a -> c -> d -> e
Translation of: C++

Translation of the C++ solution, and all the complexities are the same as in the C++ solution. In particular, we again use a self-balancing binary search tree (Set) to implement the priority queue, which results in an optimal complexity. <lang ocaml>type vertex = int type weight = float type neighbor = vertex * weight module VertexSet = Set.Make(struct type t = weight * vertex let compare = compare end)

let dijkstra (src:vertex) (adj_list:neighbor list array) : weight array * vertex array =

 let n = Array.length adj_list in
 let min_distance = Array.make n infinity in
 min_distance.(src) <- 0.;
 let previous = Array.make n (-1) in
 let rec aux vertex_queue =
   if not (VertexSet.is_empty vertex_queue) then
     let dist, u = VertexSet.min_elt vertex_queue in
     let vertex_queue' = VertexSet.remove (dist, u) vertex_queue in
     let edges = adj_list.(u) in
     let f vertex_queue (v, weight) =
       let dist_thru_u = dist +. weight in
       if dist_thru_u >= min_distance.(v) then
         vertex_queue
       else begin
         let vertex_queue' = VertexSet.remove (min_distance.(v), v) vertex_queue in
         min_distance.(v) <- dist_thru_u;
         previous.(v) <- u;
         VertexSet.add (min_distance.(v), v) vertex_queue'
       end
     in
     aux (List.fold_left f vertex_queue' edges)
 in
 aux (VertexSet.singleton (min_distance.(src), src));
 min_distance, previous

let shortest_path_to (target : vertex) (previous : vertex array) : vertex list =

 let rec aux target acc =
   if target = -1 then
     acc
   else
     aux previous.(target) (target :: acc)
 in
 aux target []

let adj_list =

 [| [(1, 7.); (2, 9.); (5, 14.)];           (* 0 = a *)
    [(0, 7.); (2, 10.); (3, 15.)];          (* 1 = b *)
    [(0, 9.); (1, 10.); (3, 11.); (5, 2.)]; (* 2 = c *)
    [(1, 15.); (2, 11.); (4, 6.)];          (* 3 = d *)
    [(3, 6.); (5, 9.)];                     (* 4 = e *)
    [(0, 14.); (2, 2.); (4, 9.)]            (* 5 = f *)
 |]

let () =

 let min_distance, previous = dijkstra 0 adj_list in
 Printf.printf "Distance from 0 to 4: %f\n" min_distance.(4);
 let path = shortest_path_to 4 previous in
 print_string "Path: ";
 List.iter (Printf.printf "%d, ") path;
 print_newline ()</lang>

PARI/GP

Basic, inefficient implementation. Takes an n×n matrix representing distance between nodes (a 0-1 matrix if you just want to count number of steps) and a number in 1..n representing the starting node, which defaults to 1 if not given. <lang parigp>shortestPath(G, startAt=1)={ my(n=#G[,1],dist=vector(n,i,9e99),prev=dist,Q=2^n-1); dist[startAt]=0; while(Q, my(t=vecmin(vecextract(dist,Q)),u); if(t==9e99, break); for(i=1,#v,if(dist[i]==t && bittest(Q,i-1), u=i; break)); Q-=1<<(u-1); for(i=1,n, if(!G[u,i],next); my(alt=dist[u]+G[u,i]); if (alt < dist[i], dist[i]=alt; prev[i]=u; ) ) ); dist };</lang>

PicoLisp

Following the Wikipedia algorithm: <lang PicoLisp>(de neighbor (X Y Cost)

  (push (prop X 'neighbors) (cons Y Cost))
  (push (prop Y 'neighbors) (cons X Cost)) )

(de dijkstra (Curr Dest)

  (let Cost 0
     (until (== Curr Dest)
        (let (Min T  Next)
           (for N (; Curr neighbors)
              (with (car N)
                 (let D (+ Cost (cdr N))
                    (unless (and (: distance) (>= D @))
                       (=: distance D) ) )
                 (when (> Min (: distance))
                    (setq Min (: distance)  Next This) )
                 (del (asoq Curr (: neighbors)) (:: neighbors)) ) )
           (setq Curr Next  Cost Min) ) )
     Cost ) )</lang>

Test: <lang PicoLisp>(neighbor 'a 'b 7) (neighbor 'a 'c 9) (neighbor 'a 'f 14) (neighbor 'b 'c 10) (neighbor 'b 'd 15) (neighbor 'c 'd 11) (neighbor 'c 'f 2) (neighbor 'd 'e 6) (neighbor 'e 'f 9)

(dijkstra 'a 'e)</lang> Output:

-> 20

REXX

Some program features are:

  • listing of the paths between two vertices and their cost
  • elimination of null edges
  • elimination of duplications (the cheapest path is chosen)
  • a test for a no path found condition

<lang rexx>/*REXX pgm finds the least costly path between 2 vertices given a list.*/ numeric digits 20 /*must be ≥ than any path cost.*/ $.=copies(9,digits()) /*edge cost; this means ¬ exist.*/ aList='!. @. $. beg fin bestP best$ xx yy' /*"common" variables.*/ @abc='abcdefghijklmnopqrstuvwxyz' /*list of possible vertices. */ verts=0 /*number of vertices. */ edges=0 /*number of edges. */

                       do jj=1  for length(@abc);     _=substr(@abc,jj,1)
                       call value translate(_),jj;    @@.jj=_
                       end    /*jj*/

call def$ a b 7 /*define an edge and its cost. */ call def$ a c 9 /*define an edge and its cost. */ call def$ a f 14 /*define an edge and its cost. */ call def$ b c 10 /*define an edge and its cost. */ call def$ b d 15 /*define an edge and its cost. */ call def$ c d 11 /*define an edge and its cost. */ call def$ c f 2 /*define an edge and its cost. */ call def$ d e 6 /*define an edge and its cost. */ call def$ e f 9 /*define an edge and its cost. */ beg=a /*the begin vertex. */ fin=e /*the finish vertex. */ say; say 'number of edges = ' edges

       say 'number of vertices = ' verts  "   ["left(@abc,verts)"]"

best$=$.; bestP=

                      do jv=2 to verts
                      call paths verts,jv
                      end   /*jv*/

say if bestP==$. then do; say 'no path found.'; exit; end /*oops-ay. */ say 'best path =' translate(bestP,@abc,123456789) ' cost =' best$ exit /*stick a fork in it, we're done.*/ /*──────────────────────────────────APATH subroutine────────────────────*/ apath: parse arg pathx 1 p1 2 p2 3; Lp=length(pathx); $=$.p1.p2 if $>=best$ then return pv=p2; do ka=3 to Lp; _=substr(pathx,ka,1)

                                   if $.pv._>=best$  then return
                                   $=$+$.pv._;  if $>=best$ then return
                                   pv=_
                                   end   /*ka*/

best$=$; bestP=pathx return /*──────────────────────────────────DEF$ subroutine─────────────────────*/ def$: parse arg xx yy $ .; if $.xx.yy<$ & $.yy.xx<$ | xx=yy then return edges=edges+1; verts=verts + ($.xx\==0) + ($.yy\==0) $.xx=0; $.yy=0; $.xx.yy=$; $.yy.xx=$ say left(,40) "cost of " @@.xx '◄───►' @@.yy " is " $ return /*──────────────────────────────────PATHS subroutine────────────────────*/ paths: procedure expose (aList); parse arg xx,yy,@.

               do kp=1  for xx;    _=kp;    !.kp=_   /*build path list.*/
               end   /*kp*/

call .paths 1 return /*──────────────────────────────────.PATHS subroutine───────────────────*/ .paths: procedure expose (aList); parse arg ?,_ if ?>yy then do

            if @.1\==beg | @.yy\==fin then return
                                   do jj=1 for yy;   _=_||@.jj
                                   end   /*jj*/
            call apath _
            end
       else do qq=1  for xx           /*build vertex paths recursively.*/
                                   do kp=1  for ?-1
                                   if @.kp==!.qq  then iterate qq
                                   end   /*kp*/
            @.?=!.qq;  call .paths ?+1
            end   /*qq*/

return</lang> output when using the input of: xxx

                                         cost of    a ◄───► b    is  7
                                         cost of    a ◄───► c    is  9
                                         cost of    a ◄───► f    is  14
                                         cost of    b ◄───► c    is  10
                                         cost of    b ◄───► d    is  15
                                         cost of    c ◄───► d    is  11
                                         cost of    c ◄───► f    is  2
                                         cost of    d ◄───► e    is  6
                                         cost of    e ◄───► f    is  9

number of    edges =  9
number of vertices =  6    [abcdef]

best path = acfe           cost = 20

Ruby

This solution is incorrect. Since the path is directed and f is only a sink, f cannot be in the middle of a path.

Works with: Ruby version 1.9.2+

(for INFINITY)

Notes for this solution:

  • At every iteration, the next minimum distance node found by linear traversal of all nodes, which is inefficient.

<lang ruby>class Graph

 Vertex = Struct.new(:name, :neighbours, :dist, :prev)
 Edge = Struct.new(:v1, :v2, :distance)
 class Edge
   def vertices; [v1, v2]; end
 end
 def initialize(graph)
   @vertices = {}
   @edges = []
   graph.each do |(v1, v2, dist)|
     @vertices[v1] = Vertex.new(v1, []) unless @vertices.has_key?(v1) 
     vert1 = @vertices[v1]
     @vertices[v2] = Vertex.new(v2, []) unless @vertices.has_key?(v2) 
     vert2 = @vertices[v2]
     vert1.neighbours << vert2
     vert2.neighbours << vert1
     @edges << Edge.new(vert1, vert2, dist)
   end
   @dijkstra_source = nil
 end
 attr_reader :vertices, :edges
 def edge(u, v)
   @edges.find {|e| e.vertices == [u, v] or e.vertices == [v, u]}
 end
 def dijkstra(source)
   q = vertices.values
   q.each {|v| v.dist = Float::INFINITY}
   source.dist = 0
   until q.empty?
     u = q.min_by {|vertex| vertex.dist}
     break if u == Float::INFINITY
     q.delete(u)
     u.neighbours.each do |v|
       if q.include?(v)
         alt = u.dist + edge(u,v).distance
         if alt < v.dist
           v.dist = alt
           v.prev = u
         end
       end
     end
   end
   @dijkstra_source = source
 end
 def shortest_path(source, target)
   dijkstra(source) unless @dijkstra_source == source
   path = []
   u = target
   until u.nil?
     path.unshift(u)
     u = u.prev
   end
   path
 end
 def to_s
   "#<%s vertices=%s edges=%s>" % [self.class.name, vertices.values.inspect, edges.inspect] 
 end

end

g = Graph.new([ [:a, :b, 7],

               [:a, :c, 9],
               [:b, :c, 10],
               [:b, :d, 15],
               [:c, :d, 11],
               [:d, :e, 6],
               [:a, :f, 14],
               [:c, :f, 2],
               [:e, :f, 9],
             ])

start = g.vertices[:a] stop = g.vertices[:e] path = g.shortest_path(start, stop) puts "shortest path from #{start.name} to #{stop.name} has cost #{stop.dist}:" puts path.map {|vertex| vertex.name}.join(" -> ")</lang>

output

shortest path from a to e has cost 20:
a -> c -> f -> e

Tcl

Note that this code traverses the entire set of unrouted nodes at each step, as this is simpler than computing the subset that are reachable at each stage. <lang tcl>proc dijkstra {graph origin} {

   # Initialize
   dict for {vertex distmap} $graph {

dict set dist $vertex Inf dict set path $vertex {}

   }
   dict set dist $origin 0
   dict set path $origin [list $origin]
   while {[dict size $graph]} {

# Find unhandled node with least weight set d Inf dict for {uu -} $graph { if {$d > [set dd [dict get $dist $uu]]} { set u $uu set d $dd } }

# No such node; graph must be disconnected if {$d == Inf} break

# Update the weights for nodes lead to by the node we've picked dict for {v dd} [dict get $graph $u] { if {[dict exists $graph $v]} { set alt [expr {$d + $dd}] if {$alt < [dict get $dist $v]} { dict set dist $v $alt dict set path $v [list {*}[dict get $path $u] $v] } } }

# Remove chosen node from graph still to be handled dict unset graph $u

   }
   return [list $dist $path]

}</lang> Showing the code in use: <lang tcl>proc makeUndirectedGraph arcs {

   # Assume that all nodes are connected to something
   foreach arc $arcs {

lassign $arc v1 v2 cost dict set graph $v1 $v2 $cost dict set graph $v2 $v1 $cost

   }
   return $graph

} set arcs {

   {a b 7} {a c 9} {b c 10} {b d 15} {c d 11}
   {d e 6} {a f 14} {c f 2} {e f 9}

} lassign [dijkstra [makeUndirectedGraph $arcs] "a"] costs path puts "path from a to e costs [dict get $costs e]" puts "route from a to e is: [join [dict get $path e] { -> }]"</lang> Output:

path from a to e costs 20
route from a to e is: a -> c -> f -> e