Dijkstra's algorithm

From Rosetta Code
Jump to: navigation, search
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 current wikipedia article is at Dijkstra's algorithm. The original RosettaCode article was extracted from the wikipedia article № 295012245 of 17:56, 7 June 2009‎‎ . The list of authors can be seen in the page history. As with Rosetta Code, the pre 5 June 2009 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.

Contents

[edit] ALGOL 68

Works with: ALGOL 68 version Revision 1 - one minor extension to language used - PRAGMA READ, similar to C's #include directive.
Works with: ALGOL 68G version Any - tested with release algol68g-2.6.
File: prelude_dijkstras_algorithm.a68
# -*- coding: utf-8 -*- #
 
COMMENT REQUIRED BY "prelude_dijkstras_algorithm.a68" CO
MODE ROUTELEN = ~;
ROUTELEN route len infinity = max ~;
PROC route len add = (VERTEX v, ROUTE r)ROUTELEN:
route len OF v + route len OF r; # or MAX(v,r) #
MODE VERTEXPAYLOAD = ~;
PROC dijkstra fix value error = (STRING msg)BOOL:
(put(stand error, (msg, new line)); FALSE);
#PROVIDES:#
# VERTEX*=~* #
# ROUTE*=~* #
# vertex route*=~* #
END COMMENT
 
MODE VALVERTEX = STRUCT(
ROUTELEN route len,
FLEX[0]ROUTE route,
ROUTE shortest route,
VERTEXPAYLOAD vertex data
);
 
MODE VERTEX = REF VALVERTEX;
MODE VERTEXYIELD = PROC(VERTEX)VOID; # used to "generate" VERTEX path #
PRIO INIT = 1; # The same PRIOrity as +:= etc #
OP INIT = (VERTEX self, VERTEXPAYLOAD vertex data)VERTEX:
self := (route len infinity, (), NIL, vertex data);
 
# It may be faster to preallocate "queue", rather then grow a FLEX #
OP +:= = (REF FLEX[]VERTEX in list, VERTEX rhs)REF FLEX[]VERTEX: (
[UPB in list+1]VERTEX out list;
out list[:UPB in list] := in list;
out list[UPB out list] := rhs;
in list := out list # EXIT #
);
 
MODE VALROUTE = STRUCT(VERTEX from, to, ROUTELEN route len#, ROUTEPAYLOAD#);
MODE ROUTE = REF VALROUTE;
 
OP +:= = (REF FLEX[]ROUTE in list, ROUTE rhs)REF FLEX[]ROUTE: (
[UPB in list+1]ROUTE out list;
out list[:UPB in list] := in list;
out list[UPB out list] := rhs;
in list := out list # EXIT #
);
 
MODE VERTEXROUTE = UNION(VERTEX, ROUTE);
MODE VERTEXROUTEYIELD = PROC(VERTEXROUTE)VOID;
 
################################################################
# Finally: now the strong typing is in place, the task code... #
################################################################
PROC vertex route gen dijkstra = (
VERTEX source, target,
REF[]VALROUTE route list,
VERTEXROUTEYIELD yield
)VOID:(
 
# initialise the route len for BOTH directions on each route #
FOR this TO UPB route list DO
ROUTE route = route list[this];
route OF from OF route +:= route;
# assume route lens is the same in both directions, this i.e. NO A-B gradient NOR 1-way streets #
route OF to OF route +:= (HEAP VALROUTE := (to OF route, from OF route, route len OF route))
OD;
 
COMMENT
Algorithium Performance "about" O(n**2)...
Optimisations:
a) bound index in [lwb queue:UPB queue] for search
b) delay adding vertices until they are actually encountered
It may be faster to preallocate "queue" vertex list, rather then grow a FLEX
END COMMENT
 
PROC vertex gen nearest = (REF FLEX[]VERTEX queue, VERTEXYIELD yield)VOID: (
INT vertices done := 0, lwb queue := 1;
ROUTELEN shortest route len done := -route len infinity;
WHILE vertices done <= UPB queue ANDF shortest route len done NE route len infinity DO
ROUTELEN shortest route len := route len infinity;
# skip done elements: #
FOR this FROM lwb queue TO UPB queue DO
VERTEX this vertex := queue[this];
IF NOT(shortest route len done < route len OF this vertex) THEN
lwb queue := this; # remember for next time #
break
FI
OD;
break:
# find vertex with shortest path attached #
FOR this FROM lwb queue TO UPB queue DO VERTEX this vertex := queue[this];
IF shortest route len done < route len OF this vertex ANDF
route len OF this vertex < shortest route len THEN
shortest route len := route len OF this vertex FI
OD;
# update the other vertices with shortest path found #
FOR this FROM lwb queue TO UPB queue DO VERTEX this vertex := queue[this];
IF route len OF this vertex = shortest route len THEN
vertices done +:= 1; yield(this vertex) FI
OD;
shortest route len done := shortest route len
OD
);
 
route len OF target := 0;
FLEX[0]VERTEX queue := target;
 
# FOR VERTEX this vertex IN # vertex gen nearest(queue#) DO (#,
## (VERTEX this vertex)VOID: (
FOR this TO UPB route OF this vertex DO ROUTE this route = (route OF this vertex)[this];
 
# If this vertex has not been encountered before, then add to queue #
IF route len OF to OF this route = route len infinity THEN queue +:= to OF this route FI;
 
ROUTELEN route len = route len add(this vertex, this route);
IF route len < route len OF to OF this route THEN
route len OF to OF this route := route len;
shortest route OF to OF this route := this route
FI
OD;
 
IF this vertex IS source THEN done FI
# OD#));
IF NOT dijkstra fix value error("no path found") THEN stop FI;
 
############################
# Now: generate the result #
############################
done: (
VERTEX this vertex := source;
WHILE
yield(this vertex);
ROUTE this route = shortest route OF this vertex;
# WHILE # this route ISNT ROUTE(NIL) DO
yield(this route);
this vertex := from OF this route
OD
)
);
 
SKIP
File: test_dijkstras_algorithm.a68
#!/usr/bin/a68g --script #
# -*- coding: utf-8 -*- #
 
CO REQUIRED BY "prelude_dijkstras_algorithm.a68" CO
MODE ROUTELEN = INT,
ROUTELEN route len infinity = max int,
PROC route len add = (VERTEX v, ROUTE r)ROUTELEN:
route len OF v + route len OF r; # or MAX(v,r) #
MODE VERTEXPAYLOAD = STRING,
PROC dijkstra fix value error = (STRING msg)BOOL:
(put(stand error, (msg, new line)); FALSE);
#PROVIDES:#
# VERTEX*=~* #
# ROUTE*=~* #
# vertex route*=~* #
PR READ "prelude_dijkstras_algorithm.a68" PR;
 
FORMAT vertex data fmt = $g$;
 
main:(
INT upb graph = 6, upb route list = 9;
 
HEAP[upb graph]VALVERTEX graph;
 
# name the key vertices #
FOR this TO UPB graph DO graph[this] INIT STRING("abcdef"[this]) OD;
 
# declare some variables of the same name #
VERTEX a := graph[1], b := graph[2], c := graph[3],
d := graph[4], e := graph[5], f := graph[6];
 
# define the graph #
HEAP FLEX[upb route list]VALROUTE route list := (
(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)
);
 
# FOR VERTEXROUTE vertex route IN # vertex route gen dijkstra(a, e, route list#) DO #,
## (VERTEXROUTE vertex route)VOID: (
CASE vertex route IN
(VERTEX vertex): printf((vertex data fmt, vertex data OF vertex)),
(ROUTE route): printf(($" --"g(0)"-> "$, route len OF route))
ESAC
# OD #));
print(new line)
 
# TODO: generate random 100000 VERTEX graph test case and test performance - important #
 
)
Output:
a --9-> c --2-> f --9-> e

[edit] 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.

#include <stdio.h>
#include <stdlib.h>
#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 --- */
#ifdef BIG_EXAMPLE
# define BLOCK_SIZE (1024 * 32 - 1)
#else
# define BLOCK_SIZE 15
#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)
{
#ifndef BIG_EXAMPLE
int i;
 
# 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);
 
# 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);
# undef E
 
#else /* BIG_EXAMPLE */
int i, j, c;
 
# 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);
}
}
 
#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');
}
 
#if 0
/* real programmers don't free memories (they use Fortran) */
free_edges();
free(heap);
free(nodes);
#endif
return 0;
}
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)

[edit] 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.

#include <iostream>
#include <vector>
#include <string>
#include <list>
 
#include <limits> // for numeric_limits
 
#include <set>
#include <utility> // for pair
#include <algorithm>
#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;
}

[edit] D

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).

import std.stdio, std.typecons, std.algorithm, std.container;
 
alias Vertex = string;
alias Weight = int;
 
const struct Neighbor {
Vertex target;
Weight weight;
}
 
alias AdjacencyMap = Neighbor[][Vertex];
 
Tuple!(Weight[Vertex], Vertex[Vertex])
dijkstraComputePaths(in Vertex source,
in Vertex target,
in AdjacencyMap adjacencyMap) pure {
typeof(typeof(return)[0]) minDistance;
foreach (immutable v, const neighs; adjacencyMap) {
minDistance[v] = Weight.max;
foreach (immutable n; neighs)
minDistance[n.target] = Weight.max;
}
 
minDistance[source] = 0;
alias Pair = Tuple!(Weight, Vertex);
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 (immutable n; adjacencyMap.get(u, null)) {
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() {
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)];
 
AdjacencyMap adj;
foreach (immutable arc; arcs) {
adj[arc[0]] ~= Neighbor(arc[1], arc[2]);
// Add this if you want an undirected graph:
//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));
}
Output:
Distance from "a" to "e": 26
Path: ["a", "c", "d", "e"]

[edit] 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.

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
}
Output:
Directed graph with 6 nodes, 9 edges
Shortest path(s):
[a c d e] length 26

[edit] 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.

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

[edit] Icon and Unicon

This Unicon-only solution is an adaptation of the Unicon parallel maze solver found in Maze solving. It searches paths in the graph in parallel until all possible shortest paths from the start node to the finish node have been discovered and then outputs the shortest path.

procedure main(A)
graph := getGraph()
repeat {
writes("What is the start node? ")
start := \graph.nodes[read()] | stop()
writes("What is the finish node? ")
finish := read() | stop()
 
QMouse(graph,start,finish)
waitForCompletion() # block until all quantum mice have finished
 
showPath(getBestMouse(),start.name,finish)
cleanGraph(graph)
}
end
 
procedure getGraph()
graph := Graph(table(),table())
write("Enter edges as 'n1,n2,weight' (blank line terminates)")
repeat {
if *(line := trim(read())) = 0 then break
line ? {
n1 := 1(tab(upto(',')),move(1))
n2 := 1(tab(upto(',')),move(1))
w := tab(0)
/graph.nodes[n1] := Node(n1,set())
/graph.nodes[n2] := Node(n2,set())
insert(graph.nodes[n1].targets,graph.nodes[n2])
graph.weights[n1||":"||n2] := w
}
}
return graph
end
 
procedure showPath(mouse,start,finish)
if \mouse then {
path := mouse.getPath()
writes("Weight: ",path.weight," -> ")
every writes(" ",!path.nodes)
write("\n")
}
else write("No path from ",start," to ",finish,"\n")
end
 
# A "Quantum-mouse" for traversing graphs. Each mouse lives for just
# one node but can spawn additional mice to search adjoining nodes.
 
global qMice, goodMice, region, qMiceEmpty
 
record Graph(nodes,weights)
record Node(name,targets,weight)
record Path(weight, nodes)
 
class QMouse(graph, loc, finish, path)
 
method getPath(); return path; end
method atEnd(); return (finish == loc.name); end
 
method visit(n) # Visit if we don't already have a cheaper route to n
newWeight := path.weight + graph.weights[loc.name||":"||n.name]
critical region[n]: if /n.weight | (newWeight < n.weight) then {
n.weight := newWeight
unlock(region[n])
return n
}
end
 
initially (g, l, f, p)
initial { # Construct critical region mutexes and completion condvar
qMiceEmpty := condvar()
region := table()
every region[n := !g.nodes] := mutex()
qMice := mutex(set())
cleanGraph(g)
}
graph := g
loc := l
finish := f
/p := Path(0,[])
path := Path(p.weight,copy(p.nodes))
if *path.nodes > 0 then
path.weight +:= g.weights[path.nodes[-1]||":"||loc.name]
put(path.nodes, loc.name)
insert(qMice,self)
thread {
if atEnd() then insert(goodMice, self) # This mouse found a finish
every QMouse(g,visit(!loc.targets),f,path)
delete(qMice, self) # Kill this mouse
if *qMice=0 then signal(qMiceEmpty) # All mice are dead
}
end
 
procedure cleanGraph(graph)
every (!graph.nodes).weight := &null
goodMice := mutex(set())
end
 
procedure getBestMouse()
every mouse := !goodMice do { # Locate shortest path
weight := mouse.getPath().weight
/minPathWeight := weight
if minPathWeight >=:= weight then bestMouse := mouse
}
return bestMouse
end
 
procedure waitForCompletion()
critical qMiceEmpty: while *qMice > 0 do wait(qMiceEmpty)
end

Sample run:

-> dSolve
Enter edges as 'n1,n2,weight' (blank line terminates)
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

What is the start node? a
What is the finish node? f
Weight: 11 ->  a c f

What is the start node? a
What is the finish node? e
Weight: 26 ->  a c d e

What is the start node? f
What is the finish node? a
No path from f to a

What is the start node?
->

[edit] J

 
NB. verbs and adverb
parse_table=: ;:@:(LF&= [;._2 -.&CR)
mp=: $:~ :(+/ .*) NB. matrix product
min=: <./ NB. minimum
Index=: (i.`)(`:6) NB. Index adverb
 
dijkstra=: dyad define
'LINK WEIGHT'=. , (0 _ ,. 2) <;.3 y
'SOURCE SINK'=. |: LINK
FRONTIER=. , < {. x
GOAL=. {: x
enumerate=. 2&([\)&.>
while. FRONTIER do.
PATH_MASK=. FRONTIER (+./@:(-:"1/)&:>"0 _~ enumerate)~ LINK
I=. PATH_MASK min Index@:mp WEIGHTS
PATH=. I >@{ FRONTIER
STATE=. {: PATH
if. STATE -: GOAL do. PATH return. end.
FRONTIER=. (<<< I) { FRONTIER NB. elision
ADJACENCIES=. (STATE = SOURCE) # SINK
FRONTIER=. FRONTIER , PATH <@,"1 0 ADJACENCIES
end.
EMPTY
)
 
 
 
NB. The specific problem
 
INPUT=: noun define
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
)
 
T=: parse_table INPUT
NAMED_LINKS=: _ 2 {. T
NODES=: ~. , NAMED_LINKS NB. vector of boxed names
NUMBERED_LINKS=: NODES i. NAMED_LINKS
WEIGHTS=: _ ".&> _ _1 {. T
GRAPH=: NUMBERED_LINKS ,. WEIGHTS NB. GRAPH is the numerical representation
 
 
TERMINALS=: NODES (i. ;:) 'a e'
 
NODES {~ TERMINALS dijkstra GRAPH
 
Note 'Output'
┌─┬─┬─┬─┐
│a│c│d│e│
└─┴─┴─┴─┘
 
TERMINALS and GRAPH are integer arrays:
 
TERMINALS
0 5
 
GRAPH
0 1 7
0 2 9
0 3 14
1 2 10
1 4 15
2 4 11
2 3 2
4 5 6
5 3 9
)

 

[edit] 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.
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();
}
}

[edit] 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.

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"}

Mma dijkstra.PNG

[edit] 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]] */

[edit] OCaml

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

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)

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.

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 ()

[edit] 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.

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
};

[edit] Perl 6

 
class Graph {
has (%.edges, %.nodes);
 
method new(*@args){
my (%edges, %nodes);
for @args {
%edges{.[0]~.[1]} = $_;
%nodes{.[0]}.push(.[0]~.[1]);
%nodes{.[1]}.push(.[0]~.[1]);}
self.bless(edges => %edges, nodes => %nodes);}
 
method neighbours ($source){
my (%neighbours, $edges);
$edges = self.nodes{$source};
for @$edges -> $x{
for self.edges{$x}[0..1] -> $y{if $y ne $source {%neighbours{$y} = self.edges{$x}}}
}
return %neighbours}
 
method dijkstra ($source, $dest) {
my (%node_data, $v, $u); my @q = self.nodes.keys;
 
for self.nodes.keys {%node_data{$_}{'dist'} = Inf;%node_data{$_}{'prev'} = '';}
%node_data{$source}{'dist'} = 0;
 
while @q {# %node_data.perl.say;
my ($mindist, $idx) = @((map {[%node_data{@q[$_]}{'dist'},$_]},^@q).min(*[0]));
$u = @q[$idx];
 
if $mindist eq Inf {return ()}
 
elsif $u eq $dest {
my @s;
while %node_data{$u}{'prev'} {@s.unshift($u); $u = %node_data{$u}{'prev'}}
@s.unshift($source);
return @s;}
 
else {@q.splice($idx,1);}
 
for self.neighbours($u).kv -> $v, $edge{
my $alt = %node_data{$u}{'dist'} + $edge[2];
if $alt < %node_data{$v}{'dist'} {
%node_data{$v}{'dist'} = $alt;
%node_data{$v}{'prev'} = $u;}
}
}
}
}
 
my $a = Graph.new(["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]).dijkstra('a', 'e').say;
 
Output:
a c f e

[edit] PHP

There are parts of this algorithm that could be optimized which have been marked TODO.

 
<?php
function dijkstra($graph_array, $source, $target) {
$vertices = array();
$neighbours = array();
foreach ($graph_array as $edge) {
array_push($vertices, $edge[0], $edge[1]);
$neighbours[$edge[0]][] = array("end" => $edge[1], "cost" => $edge[2]);
}
$vertices = array_unique($vertices);
 
foreach ($vertices as $vertex) {
$dist[$vertex] = INF;
$previous[$vertex] = NULL;
}
 
$dist[$source] = 0;
$Q = $vertices;
while (count($Q) > 0) {
 
// TODO - Find faster way to get minimum
$min = INF;
foreach ($Q as $vertex){
if ($dist[$vertex] < $min) {
$min = $dist[$vertex];
$u = $vertex;
}
}
 
$Q = array_diff($Q, array($u));
if ($dist[$u] == INF or $u == $target) {
break;
}
 
if (isset($neighbours[$u])) {
foreach ($neighbours[$u] as $arr) {
$alt = $dist[$u] + $arr["cost"];
if ($alt < $dist[$arr["end"]]) {
$dist[$arr["end"]] = $alt;
$previous[$arr["end"]] = $u;
}
}
}
}
$path = array();
$u = $target;
while (isset($previous[$u])) {
array_unshift($path, $u);
$u = $previous[$u];
}
array_unshift($path, $u);
return $path;
}
 
$graph_array = array(
array("a", "b", 7),
array("a", "c", 9),
array("a", "f", 14),
array("b", "c", 10),
array("b", "d", 15),
array("c", "d", 11),
array("c", "f", 2),
array("d", "e", 6),
array("e", "f", 9)
);
 
$path = dijkstra($graph_array, "a", "e");
 
echo "path is: ".implode(", ", $path)."\n";
 

Output is:

path is: a, c, d, e

[edit] PicoLisp

Following the Wikipedia algorithm:

(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 ) )

Test:

(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)

Output:

-> 20

[edit] Prolog

An implementation of Dijkstra's algorithm in Prolog

Dijkstra's algorithm starts with a set of all unvisited nodes, assigning an initial distance value for each as infinite. It then attempts to minimise the distance for each node from the origin.

Starting at the origin (distance 0), the algorithm checks each neighbor's distance value and if larger than the current path distance, replaces the neighboring node's distance value. It then marks the current node as visited, and repeats the process for each of the neighbors. When the current node becomes the destination, the distance to the origin is known.

This implementation is a slight variation on Dijkstra, which lends itself to Prolog's strengths while retaining approximate algorithmic equivalence.

Prolog is not good at modifying memory in place, but is quite good at handling facts, pattern matching, recursion and backtracking to find all possible solutions.

A dynamic database predicate, namely:

    rpath([target|reversed_path], distance)   

stores the currently known shortest distance and best path to a destination from the origin. Since the path is a reversed list, the first item in the list is the destination node, and the predicate is efficiently matched.

Instead of using unvisited flags on nodes, we test whether neighbors are already in the traversed path. This achieves the same thing as 'visited' flags, but in a way that is more efficient for Prolog.

After the graph traversal is complete, we are left with a single rpath/2 predicate for each reachable node, containing the shortest path and distance from the origin.

Subtle differences

1) Dijkstra visits each node only once, starting with the origin. This algorithm:

   - arbitrarily selects a node (Qi) neighboring origin (o), and for that node
   - if o->Qi is the shortest known path:
       - update path and distance
       - traverse Qi
   - if o->Qi is not the shortest, select the next node.

It is possible therefore, contrary to Dijkstra, that we may visit a node more than once whilst discovering a shorter path. It is also possible that the first path we choose is already the shortest eliminating processing.

2) As traversal spreads outwards, the path is built as a list of traversed nodes.

   - We use this list to ensure that we do not loop endlessly.
   - This path is recorded as the shortest if the distance is indeed shorter than a known path.
   - Leaf nodes in the traversal tree are processed completely before the origin node processing 
     is completed. 
     - This implies that the first stage in our algorithm involves allocating each node
       in the traversal tree a path and 'shortest known distance from origin' value.
     - ...Which is arguably better than assigning an initial 'infinite distance' value.

We could possibly improve our algorithm by processing the neighbor with the shortest distance first, rather than an arbitrary selection as is currently the case. There is nothing though, to suggest that the eventual shortest path found would necessarily follow the shortest initial path, unless the target node is already the closest neighbor.


%___________________________________________________________________________
 
:-dynamic
rpath/2. % A reversed path
 
edge(a,b,7).
edge(a,c,9).
edge(b,c,10).
edge(b,d,15).
edge(c,d,11).
edge(d,e,6).
edge(a,f,14).
edge(c,f,2).
edge(e,f,9).
 
path(From,To,Dist) :- edge(To,From,Dist).
path(From,To,Dist) :- edge(From,To,Dist).
 
shorterPath([H|Path], Dist) :- % path < stored path? replace it
rpath([H|T], D), !, Dist < D, % match target node [H|_]
retract(rpath([H|_],_)),
writef('%w is closer than %w\n', [[H|Path], [H|T]]),
assert(rpath([H|Path], Dist)).
shorterPath(Path, Dist) :- % Otherwise store a new path
writef('New path:%w\n', [Path]),
assert(rpath(Path,Dist)).
 
traverse(From, Path, Dist) :- % traverse all reachable nodes
path(From, T, D), % For each neighbor
not(memberchk(T, Path)), % which is unvisited
shorterPath([T,From|Path], Dist+D), % Update shortest path and distance
traverse(T,[From|Path],Dist+D). % Then traverse the neighbor
 
traverse(From) :-
retractall(rpath(_,_)), % Remove solutions
traverse(From,[],0). % Traverse from origin
traverse(_).
 
go(From, To) :-
traverse(From), % Find all distances
rpath([To|RPath], Dist)-> % If the target was reached
reverse([To|RPath], Path), % Report the path and distance
Distance is round(Dist),
writef('Shortest path is %w with distance %w = %w\n',
[Path, Dist, Distance]);
writef('There is no route from %w to %w\n', [From, To]).
 

for example:

?- go(a,e).
New path:[b,a]
New path:[c,b,a]
New path:[d,c,b,a]
New path:[e,d,c,b,a]
New path:[f,e,d,c,b,a]
[f,c,b,a] is closer than [f,e,d,c,b,a]
[e,f,c,b,a] is closer than [e,d,c,b,a]
[d,b,a] is closer than [d,c,b,a]
[c,a] is closer than [c,b,a]
[d,c,a] is closer than [d,b,a]
[e,d,c,a] is closer than [e,f,c,b,a]
[f,c,a] is closer than [f,c,b,a]
[e,f,c,a] is closer than [e,d,c,a]
Shortest path is [a,c,f,e] with distance 0+9+2+9 = 20
true.

[edit] Python

Starts from the wp:Dijkstra's_algorithm#Pseudocode recognising that their function dist_between is what this task calls cost; and that their action decrease-key v in Q at their line 24 should be omitted if their Q is a set as stated in their line 9. The wp back-tracking pseudocode also misses a final insert of u at the beginning of S that must occur after exiting their while loop.

Note: q could be changed to be a priority queue instead of a set as mentioned here.

from collections import namedtuple
from pprint import pprint as pp
 
 
inf = float('inf')
Edge = namedtuple('Edge', 'start, end, cost')
 
class Graph():
def __init__(self, edges):
self.edges = edges2 = [Edge(*edge) for edge in edges]
self.vertices = set(sum(([e.start, e.end] for e in edges2), []))
 
def dijkstra(self, source, dest):
assert source in self.vertices
dist = {vertex: inf for vertex in self.vertices}
previous = {vertex: None for vertex in self.vertices}
dist[source] = 0
q = self.vertices.copy()
neighbours = {vertex: set() for vertex in self.vertices}
for start, end, cost in self.edges:
neighbours[start].add((end, cost))
#pp(neighbours)
 
while q:
u = min(q, key=lambda vertex: dist[vertex])
q.remove(u)
if dist[u] == inf or u == dest:
break
for v, cost in neighbours[u]:
alt = dist[u] + cost
if alt < dist[v]: # Relax (u,v,a)
dist[v] = alt
previous[v] = u
#pp(previous)
s, u = [], dest
while previous[u]:
s.insert(0, u)
u = previous[u]
s.insert(0, u)
return s
 
 
graph = 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)])
pp(graph.dijkstra("a", "e"))
Output:
['a', 'c', 'd', 'e']

[edit] Racket

 
#lang racket
(require (planet jaymccarthy/dijkstra:1:2))
 
(define edges
'([a . ((b 7)(c 9)(f 14))]
[b . ((c 10)(d 15))]
[c . ((d 11)(f 2))]
[d . ((e 6))]
[e . ((f 9))]))
 
(define (node-edges n)
(cond [(assoc n edges) => rest] ['()]))
(define edge-weight second)
(define edge-end first)
 
(match/values (shortest-path node-edges edge-weight edge-end 'a (λ(n) (eq? n 'e)))
[(dists prevs)
(displayln (~a "Distances from a: " (for/list ([(n d) dists]) (list n d))))
(displayln (~a "Shortest path: "
(let loop ([path '(e)])
(cond [(eq? (first path) 'a) path]
[(loop (cons (hash-ref prevs (first path)) path))]))))])
 

Output:

 
Distances from a: ((b 7) (d 20) (a 0) (c 9) (f 11) (e 26))
Shortest path: (a c d e)
 

[edit] REXX

Some program features are:

  • elimination of null edges
  • elimination of duplications (the cheapest path is chosen)
  • a test for a no path found condition
  • use of memoization
/*REXX pgm finds the least costly path  between 2 vertices given a list.*/
$.=copies(9,digits()) /*edge cost; this means ¬ exist.*/
aList='!. @. $. beg fin bestP best$ xx yy' /*common EXPOSEd variables.*/
@abc='abcdefghijklmnopqrstuvwxyz' /*list of all possible vertices. */
 
verts=0 /*number of vertices. */
edges=0 /* " " 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 /* " " " " " " */
call def$ a f 14 /* " " " " " " */
call def$ b c 10 /* " " " " " " */
call def$ b d 15 /* " " " " " " */
call def$ c d 11 /* " " " " " " */
call def$ c f 2 /* " " " " " " */
call def$ d e 6 /* " " " " " " */
call def$ e f 9 /* " " " " " " */
beg=a; fin=e /*the BEG & 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
@.?=!.qq; call .paths ?+1
end /*qq*/
return

output when using the (internal) defaults:

                                         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

[edit] 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.
class Graph
Vertex = Struct.new(:name, :neighbours, :dist, :prev)
 
def initialize(graph)
@vertices = Hash.new{|h,k| h[k]=Vertex.new(k,[],Float::INFINITY)}
@edges = {}
graph.each do |(v1, v2, dist)|
@vertices[v1].neighbours << v2
@vertices[v2].neighbours << v1
@edges[[v1, v2]] = @edges[[v2, v1]] = dist
end
@dijkstra_source = nil
end
 
def dijkstra(source)
return if @dijkstra_source == source
q = @vertices.values
q.each do |v|
v.dist = Float::INFINITY
v.prev = nil
end
@vertices[source].dist = 0
until q.empty?
u = q.min_by {|vertex| vertex.dist}
break if u.dist == Float::INFINITY
q.delete(u)
u.neighbours.each do |v|
vv = @vertices[v]
if q.include?(vv)
alt = u.dist + @edges[[u.name, v]]
if alt < vv.dist
vv.dist = alt
vv.prev = u.name
end
end
end
end
@dijkstra_source = source
end
 
def shortest_path(source, target)
dijkstra(source)
path = []
u = target
while u
path.unshift(u)
u = @vertices[u].prev
end
return path, @vertices[target].dist
end
 
def to_s
"#<%s vertices=%p edges=%p>" % [self.class.name, @vertices.values, @edges]
end
end
 
g = Graph.new([ [: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],
])
 
start, stop = :a, :e
path, dist = g.shortest_path(start, stop)
puts "
shortest path from #{start} to #{stop} has cost #{dist}:"
puts path.join(" -> ")
Output:
shortest path from a to e has cost 20:
a -> c -> f -> e

[edit] Scala

This is a fairly straightforward translation of the Wikipedia pseudocode. It traverses the entire unvisited set every iteration to determine the next node to visit, so it's not particularly efficient.

object Dijkstra {
case class Node(name: String)
case class Edge(start: Node, end: Node, cost: Int)
 
def apply(edges: Set[Edge], source: Node, target: Node) = {
var dist = Map(source -> 0).withDefaultValue(Int.MaxValue)
var unvisiteds = edges.flatMap { case Edge(s, e, _) => Seq(s, e) }.toSet
var shortestHops = Map[Node, Node]()
 
def nodeEdges(n: Node) = edges.filter(_.start == n)
def minU = unvisiteds.reduce((a, b) => if (dist(a) < dist(b)) a else b)
 
while (unvisiteds.nonEmpty) {
val u = minU
unvisiteds -= u
for (e <- nodeEdges(u); alt = dist(u) + e.cost; if alt < dist(e.end)) {
dist += e.end -> alt
shortestHops += e.end -> u
}
}
 
def trace(u: Node, path: Seq[Node] = Seq()): Seq[Node] =
if (!shortestHops.contains(u)) u +: path
else trace(shortestHops(u), u +: path)
 
(dist(target), trace(target))
}
}
 
object DijkstraTest extends App {
import Dijkstra._
implicit def stringToNode(name: String) = Node(name)
 
val from = "a"
val to = "e"
val edges = Set(
Edge("a", "b", 7),
Edge("a", "c", 9),
Edge("a", "f", 14),
Edge("b", "c", 10),
Edge("b", "d", 15),
Edge("c", "d", 11),
Edge("c", "f", 2),
Edge("d", "e", 6),
Edge("e", "f", 9))
 
val (len, path) = Dijkstra(edges, from, to)
println(s"The shortest path from $from to $to has:")
println(s" - length: $len")
println(s" - nodes: " + path.mkString("[ ", " -> ", " ]"))
}
Output:
The shortest path from a to e has:
	length: 26
	nodes: [ Node(a) -> Node(c) -> Node(d) -> Node(e) ]

[edit] Tcl

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

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.

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]
}

Showing the code in use:

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] { -> }]"

Output:

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

Variants
Actions
Community
Explore
Misc
Toolbox