⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

'''Dijkstra's algorithm''', conceived by Dutch computer scientist [[wp:Edsger Dijkstra|Edsger Dijkstra]] in 1956 and published in 1959, is a [[wp:graph search algorithm|graph search algorithm]] that solves the single-source [[wp:shortest path problem|shortest path problem]] for a [[wp:graph (mathematics)|graph]] with non-negative [[wp:edge (graph theory)|edge]] path costs, producing a [[wp:shortest path tree|shortest path tree]].

This algorithm is often used in [[wp:routing|routing]] and as a subroutine in other graph algorithms.

For a given source [[wp:vertex (graph theory)|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.

;For instance: 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 [[wp:routing protocol|routing protocol]]s, most notably: ::* [[wp:IS-IS|IS-IS]] (Intermediate System to Intermediate System) and ::* [[wp:OSPF|OSPF]] (Open Shortest Path First).

;Important note: The inputs to Dijkstra's algorithm are a directed and weighted graph consisting of 2 or more nodes, generally represented by: ::* an adjacency matrix or list, and ::* a start node.

A destination node is not specified.

The output is a set of edges depicting the shortest path to each destination node.

;An example, starting with: a─►b, cost=7, lastNode=a a─►c, cost=9, lastNode=a a─►d, cost=NA, lastNode=a a─►e, cost=NA, lastNode=a a─►f, cost=14, lastNode=a

The lowest cost is    a─►b    so    a─►b    is added to the output.

There is a connection from   b─►d   so the input is updated to:
a─►c, cost=9,  lastNode=a
a─►d, cost=22, lastNode=b
a─►e, cost=NA, lastNode=a
a─►f, cost=14, lastNode=a

The lowest cost is    a─►c    so    a─►c    is added to the output.

Paths to    d    and    f    are cheaper via    c    so the input is updated to:
a─►d, cost=20, lastNode=c
a─►e, cost=NA, lastNode=a
a─►f, cost=11, lastNode=c

The lowest cost is    a─►f    so    c─►f    is added to the output.

The input is updated to:
a─►d, cost=20, lastNode=c
a─►e, cost=NA, lastNode=a

The lowest cost is    a─►d    so    c─►d    is added to the output.

There is a connection from    d─►e    so the input is updated to:
a─►e, cost=26, lastNode=d

Which just leaves adding    d─►e    to the output.

The output should now be:
[ d─►e
c─►d
c─►f
a─►c
a─►b ]

# Implement a version of Dijkstra's algorithm that outputs a set of edges depicting the shortest path to each reachable node from an origin.
# Run your program with the following directed graph starting at node  <big> '''a'''</big>.
# Write a program which interprets the output from the above and use it to output the shortest path from node  <big> '''a''' </big>  to nodes  <big> '''e''' </big> and  <big> '''f''' </big>.

::::::: {| class="wikitable" style="text-align: center; float: left"
|+ Vertices
|-
! Number !! Name
|-
| 1 || a
|-
| 2 || b
|-
| 3 || c
|-
| 4 || d
|-
| 5 || e
|-
| 6 || f
|}
{| class="wikitable" style="text-align: center"
|+ 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.

* [https://www.youtube.com/watch?v=cSxnOm5aceA Dijkstra's Algorithm vs. A* Search vs. Concurrent Dijkstra's Algorithm (youtube)]

{{works with|GNAT}}
This solution uses a generic package and Ada 2012 (containers, extended return statements, expression functions).
The very convenient 'Img attribute is a GNAT feature.

generic
type t_Vertex is (<>);
package Dijkstra is

type t_Graph is limited private;

-- Defining a graph (since limited private, only way to do this is to use the Build function)
type t_Edge is record
From, To : t_Vertex;
Weight   : Positive;
end record;
type t_Edges is array (Integer range <>) of t_Edge;
function Build (Edges : in t_Edges; Oriented : in Boolean := True) return t_Graph;

-- Computing path and distance
type t_Path is array (Integer range <>) of t_Vertex;
function Shortest_Path (Graph    : in out t_Graph;
From, To : in t_Vertex) return t_Path;
function Distance      (Graph    : in out t_Graph;
From, To : in t_Vertex) return Natural;

private
package Neighbor_Lists is new Ada.Containers.Ordered_Maps (Key_Type => t_Vertex, Element_Type => Positive);
type t_Vertex_Data is record
Neighbors : Neighbor_Lists.Map; -- won't be affected after build
-- Updated each time a function is called with a new source
Previous  : t_Vertex;
Distance  : Natural;
end record;
type t_Graph is array (t_Vertex) of t_Vertex_Data;
end Dijkstra;
package body Dijkstra is

Infinite : constant Natural := Natural'Last;

-- ----- Graph constructor
function Build (Edges : in t_Edges; Oriented : in Boolean := True) return t_Graph is
begin
return Answer : t_Graph := (others => (Neighbors => Neighbor_Lists.Empty_Map,
Previous  => t_Vertex'First,
Distance  => Natural'Last)) do
for Edge of Edges loop
Answer(Edge.From).Neighbors.Insert (Key => Edge.To, New_Item => Edge.Weight);
if not Oriented then
Answer(Edge.To).Neighbors.Insert (Key => Edge.From, New_Item => Edge.Weight);
end if;
end loop;
end return;
end Build;

-- ----- Paths / distances data updating in case of computation request for a new source
procedure Update_For_Source (Graph : in out t_Graph;
From  : in t_Vertex) is
function Nearer (Left, Right : in t_Vertex) return Boolean is
(Graph(Left).Distance < Graph(Right).Distance or else
(Graph(Left).Distance = Graph(Right).Distance and then Left < Right));
package Ordered is new Ada.Containers.Ordered_Sets (Element_Type => t_Vertex, "<" => Nearer);
use Ordered;
Remaining : Set := Empty_Set;
begin
-- First, let's check if vertices data are already computed for this source
if Graph(From).Distance /= 0 then
-- Reset distances and remaining vertices for a new source
for Vertex in Graph'range loop
Graph(Vertex).Distance := (if Vertex = From then 0 else Infinite);
Remaining.Insert (Vertex);
end loop;
-- ----- The Dijkstra algorithm itself
while not Remaining.Is_Empty
-- If some targets are not connected to source, at one point, the remaining
-- distances will all be infinite, hence the folllowing stop condition
and then Graph(Remaining.First_Element).Distance /= Infinite loop
declare
Nearest : constant t_Vertex := Remaining.First_Element;
procedure Update_Neighbor (Position : in Neighbor_Lists.Cursor) is
use Neighbor_Lists;
Neighbor     : constant t_Vertex := Key (Position);
In_Remaining : Ordered.Cursor    := Remaining.Find (Neighbor);
Try_Distance : constant Natural  :=
(if In_Remaining = Ordered.No_Element
then Infinite -- vertex already reached, this distance will fail the update test below
else Graph(Nearest).Distance + Element (Position));
begin
if Try_Distance < Graph(Neighbor).Distance then
-- Update distance/path data and reorder the remaining set
Remaining.Delete (In_Remaining);
Graph(Neighbor).Distance := Try_Distance;
Graph(Neighbor).Previous := Nearest;
Remaining.Insert (Neighbor);
end if;
end Update_Neighbor;
begin
Remaining.Delete_First;
Graph(Nearest).Neighbors.Iterate (Update_Neighbor'Access);
end;
end loop;
end if;
end Update_For_Source;

-- ----- Bodies for the interfaced functions
function Shortest_Path (Graph    : in out t_Graph;
From, To : in t_Vertex) return t_Path is
function Recursive_Build (From, To : in t_Vertex) return t_Path is
(if From = To then (1 => From)
else Recursive_Build(From, Graph(To).Previous) & (1 => To));
begin
Update_For_Source (Graph, From);
if Graph(To).Distance = Infinite then
raise Constraint_Error with "No path from " & From'Img & " to " & To'Img;
end if;
return Recursive_Build (From, To);
end Shortest_Path;

function Distance (Graph    : in out t_Graph;
From, To : in t_Vertex) return Natural is
begin
Update_For_Source (Graph, From);
return Graph(To).Distance;
end Distance;

end Dijkstra;

The testing main procedure :

with Dijkstra;
procedure Test_Dijkstra is
subtype t_Tested_Vertices is Character range 'a'..'f';
package Tested is new Dijkstra (t_Vertex => t_Tested_Vertices);
use Tested;
Graph : t_Graph := Build (Edges => (('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)));
procedure Display_Path (From, To : in t_Tested_Vertices) is
function Path_Image (Path : in t_Path; Start : Boolean := True) return String is
((if Start then "["
elsif Path'Length /= 0 then ","
else "") &
(if Path'Length = 0 then "]"
else Path(Path'First) & Path_Image(Path(Path'First+1..Path'Last), Start => False)));
begin
Put      ("Path from '" & From & "' to '" & To & "' = ");
Put_Line (Path_Image (Shortest_Path (Graph, From, To))
& " distance =" & Distance (Graph, From, To)'Img);
exception
when others => Put_Line("no path");
end Display_Path;
begin
Display_Path ('a', 'e');
Display_Path ('a', 'f');
New_Line;
for From in t_Tested_Vertices loop
for To in t_Tested_Vertices loop
Display_Path (From, To);
end loop;
end loop;
end Test_Dijkstra;

{{out}}

Path from 'a' to 'e' = [a,c,d,e] distance = 26
Path from 'a' to 'f' = [a,c,f] distance = 11

Path from 'a' to 'a' = [a] distance = 0
Path from 'a' to 'b' = [a,b] distance = 7
Path from 'a' to 'c' = [a,c] distance = 9
Path from 'a' to 'd' = [a,c,d] distance = 20
Path from 'a' to 'e' = [a,c,d,e] distance = 26
Path from 'a' to 'f' = [a,c,f] distance = 11
Path from 'b' to 'a' = no path
Path from 'b' to 'b' = [b] distance = 0
Path from 'b' to 'c' = [b,c] distance = 10
Path from 'b' to 'd' = [b,d] distance = 15
Path from 'b' to 'e' = [b,d,e] distance = 21
Path from 'b' to 'f' = [b,c,f] distance = 12
Path from 'c' to 'a' = no path
Path from 'c' to 'b' = no path
Path from 'c' to 'c' = [c] distance = 0
Path from 'c' to 'd' = [c,d] distance = 11
Path from 'c' to 'e' = [c,d,e] distance = 17
Path from 'c' to 'f' = [c,f] distance = 2
Path from 'd' to 'a' = no path
Path from 'd' to 'b' = no path
Path from 'd' to 'c' = no path
Path from 'd' to 'd' = [d] distance = 0
Path from 'd' to 'e' = [d,e] distance = 6
Path from 'd' to 'f' = [d,e,f] distance = 15
Path from 'e' to 'a' = no path
Path from 'e' to 'b' = no path
Path from 'e' to 'c' = no path
Path from 'e' to 'd' = no path
Path from 'e' to 'e' = [e] distance = 0
Path from 'e' to 'f' = [e,f] distance = 9
Path from 'f' to 'a' = no path
Path from 'f' to 'b' = no path
Path from 'f' to 'c' = no path
Path from 'f' to 'd' = no path
Path from 'f' to 'e' = no path
Path from 'f' to 'f' = [f] distance = 0

ALGOL 68

{{works with|ALGOL 68|Revision 1 - one minor extension to language used - PRAGMA READ, similar to C's #include directive.}} {{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-2.6 algol68g-2.6].}} {{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of '''format'''[ted] ''transput''.}} '''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) #
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,
FLEXROUTE route,
ROUTE shortest route,
);

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
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;
FLEXVERTEX 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) #
PROC dijkstra fix value error = (STRING msg)BOOL:
(put(stand error, (msg, new line)); FALSE);
#PROVIDES:#
# VERTEX*=~* #
# ROUTE*=~* #
# vertex route*=~* #

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, b := graph, c := graph,
d := graph, e := graph, f := graph;

# 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

AutoHotkey

Dijkstra(data, start){
nodes := [], dist := [], Distance := [], dist := [], prev := [], Q := [], min := "x"
for each, line in StrSplit(data, "`n" , "`r")
field := StrSplit(line,"`t"), nodes[field.1] := 1, nodes[field.2] := 1
, Distance[field.1,field.2] := field.3, Distance[field.2,field.1] := field.3
dist[start] := 0, prev[start] := ""

for node in nodes {
if (node <> start)
dist[node] := "x"
, prev[node] := ""
Q[node] := 1
}

while % ObjCount(Q) {
u := MinDist(Q, dist).2
for node, val in Q
if (node = u) {
q.Remove(node)
break
}

for v, length in Distance[u] {
alt := dist[u] + length
if (alt < dist[v])
dist[v] := alt
, prev[v] := u
}
}
return [dist, prev]
}
;-----------------------------------------------
MinDist(Q, dist){
for node , val in Q
if A_Index=1
min := dist[node], minNode := node
else
min := min < dist[node] ? min : dist[node]	, minNode := min < dist[node] ? minNode : node
return [min,minNode]
}
ObjCount(Obj){
for key, val in Obj
count := A_Index
return count
}

Examples:

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

nodes:=[], Distance := []
for each, line in StrSplit(data, "`n" , "`r")
field := StrSplit(line,"`t"), nodes[field.1] := 1, nodes[field.2] := 1
, Distance[field.1,field.2] := field.3  , Distance[field.2,field.1] := field.3

for node, v in nodes
nodeList .= (nodeList?"|":"") node (A_Index=1?"|":"")

Gui, add, Text, x200 yp, To:
Gui, add, DDL, xs vFrom gSubmit, % nodeList
Gui, add, DDL, x200 yp vTo gSubmit, % nodeList
Gui, add, ListView, xs w340 r6, From|>|To|Distance
Gui, add, Text, vT1 xs w340 r1
Gui, +AlwaysOnTop
Gui, show
Loop 4
LV_ModifyCol(A_Index, "80 Center")

Submit:
Gui, Submit, NoHide
GuiControl, , T1, % ""
LV_Delete()
if !(From && To) || (From = To)
return
res := Dijkstra(data, From)	, 	xTo := xFrom := DirectFlight := "" , origin := to
GuiControl, , T1, no routing found
if !res[1, To]              ; no possible route
return

Routing:
Loop % objCount(nodes)
for xTo , xFrom in res.2
if (xTo = To)
{
LV_Insert(1,"", xFrom, ">" , xTo, Distance[xFrom , xTo]),	To := xFrom
if (xFrom = From)
break, Routing
}
GuiControl, , T1, % "Total distance = " res.1[origin] . DirectFlight
return

esc::
GuiClose:
ExitApp
return

Outputs:

A	>	C	9
C	>	F	2
F	>	E	9
Total distance = 20

C

The priority queue is implemented as a binary heap. The heap stores an index into its data array, so it can quickly update the weight of an item already in it.

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

typedef struct {
int vertex;
int weight;
} edge_t;

typedef struct {
edge_t **edges;
int edges_len;
int edges_size;
int dist;
int prev;
int visited;
} vertex_t;

typedef struct {
vertex_t **vertices;
int vertices_len;
int vertices_size;
} graph_t;

typedef struct {
int *data;
int *prio;
int *index;
int len;
int size;
} heap_t;

void add_vertex (graph_t *g, int i) {
if (g->vertices_size < i + 1) {
int size = g->vertices_size * 2 > i ? g->vertices_size * 2 : i + 4;
g->vertices = realloc(g->vertices, size * sizeof (vertex_t *));
for (int j = g->vertices_size; j < size; j++)
g->vertices[j] = NULL;
g->vertices_size = size;
}
if (!g->vertices[i]) {
g->vertices[i] = calloc(1, sizeof (vertex_t));
g->vertices_len++;
}
}

void add_edge (graph_t *g, int a, int b, int w) {
a = a - 'a';
b = b - 'a';
vertex_t *v = g->vertices[a];
if (v->edges_len >= v->edges_size) {
v->edges_size = v->edges_size ? v->edges_size * 2 : 4;
v->edges = realloc(v->edges, v->edges_size * sizeof (edge_t *));
}
edge_t *e = calloc(1, sizeof (edge_t));
e->vertex = b;
e->weight = w;
v->edges[v->edges_len++] = e;
}

heap_t *create_heap (int n) {
heap_t *h = calloc(1, sizeof (heap_t));
h->data = calloc(n + 1, sizeof (int));
h->prio = calloc(n + 1, sizeof (int));
h->index = calloc(n, sizeof (int));
return h;
}

void push_heap (heap_t *h, int v, int p) {
int i = h->index[v] == 0 ? ++h->len : h->index[v];
int j = i / 2;
while (i > 1) {
if (h->prio[j] < p)
break;
h->data[i] = h->data[j];
h->prio[i] = h->prio[j];
h->index[h->data[i]] = i;
i = j;
j = j / 2;
}
h->data[i] = v;
h->prio[i] = p;
h->index[v] = i;
}

int min (heap_t *h, int i, int j, int k) {
int m = i;
if (j <= h->len && h->prio[j] < h->prio[m])
m = j;
if (k <= h->len && h->prio[k] < h->prio[m])
m = k;
return m;
}

int pop_heap (heap_t *h) {
int v = h->data;
int i = 1;
while (1) {
int j = min(h, h->len, 2 * i, 2 * i + 1);
if (j == h->len)
break;
h->data[i] = h->data[j];
h->prio[i] = h->prio[j];
h->index[h->data[i]] = i;
i = j;
}
h->data[i] = h->data[h->len];
h->prio[i] = h->prio[h->len];
h->index[h->data[i]] = i;
h->len--;
return v;
}

void dijkstra (graph_t *g, int a, int b) {
int i, j;
a = a - 'a';
b = b - 'a';
for (i = 0; i < g->vertices_len; i++) {
vertex_t *v = g->vertices[i];
v->dist = INT_MAX;
v->prev = 0;
v->visited = 0;
}
vertex_t *v = g->vertices[a];
v->dist = 0;
heap_t *h = create_heap(g->vertices_len);
push_heap(h, a, v->dist);
while (h->len) {
i = pop_heap(h);
if (i == b)
break;
v = g->vertices[i];
v->visited = 1;
for (j = 0; j < v->edges_len; j++) {
edge_t *e = v->edges[j];
vertex_t *u = g->vertices[e->vertex];
if (!u->visited && v->dist + e->weight <= u->dist) {
u->prev = i;
u->dist = v->dist + e->weight;
push_heap(h, e->vertex, u->dist);
}
}
}
}

void print_path (graph_t *g, int i) {
int n, j;
vertex_t *v, *u;
i = i - 'a';
v = g->vertices[i];
if (v->dist == INT_MAX) {
printf("no path\n");
return;
}
for (n = 1, u = v; u->dist; u = g->vertices[u->prev], n++)
;
char *path = malloc(n);
path[n - 1] = 'a' + i;
for (j = 0, u = v; u->dist; u = g->vertices[u->prev], j++)
path[n - j - 2] = 'a' + u->prev;
printf("%d %.*s\n", v->dist, n, path);
}

int main () {
graph_t *g = calloc(1, sizeof (graph_t));
dijkstra(g, 'a', 'e');
print_path(g, 'e');
return 0;
}

output

26 acde

C++

(Modified from [http://en.literateprograms.org/Dijkstra%27s_algorithm_%28C_Plus_Plus%29 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.

The time complexity of this algorithm is O(E log V), as described on Wikipedia. Each vertex is added to the priority queue at most once (re-ordering doesn't count as adding), because once it's in the priority queue, we only re-order it, never add it again. And when it's popped from the priority queue, that means we already have the real minimum distance to this vertex, so the relaxation condition will always fail in the future for this vertex, and it will never be added to the priority queue again. Therefore, we will only pop each vertex at most once from the priority queue, and the size of the priority queue is bounded by V (the number of vertexes).

The outer loop executes once for each element popped from the priority queue, so it will execute at most once for each vertex, so at most V times. Each iteration of the outer loop executes one pop from the priority queue, which has time complexity O(log V). The inner loop executes at most once for each directed edge, since each directed edge has one originating vertex, and there is only at most one iteration of the outer loop for each vertex. Each iteration of the inner loop potentially performs one push or re-order on the priority queue (where re-order is a pop and a push), which has complexity O(log V). There is also the O(V) complexity for initializing the data structures. Combining these, we have a complexity of O(V log V + E log V), and assuming this is a connected graph, V <= E+1 = O(E), so we can write it as O(E log V).

#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) { }
};

void DijkstraComputePaths(vertex_t source,
std::vector<weight_t> &min_distance,
std::vector<vertex_t> &previous)
{
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
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
// 0 = a
// 1 = b
// 2 = c
// 3 = d
// 4 = e
// 5 = f

std::vector<weight_t> min_distance;
std::vector<vertex_t> previous;
std::cout << "Distance from 0 to 4: " << min_distance << 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;
}

Note that it ''is'' possible to use C++ built-in heaps (or the abstract std::priority_queue datatype) to implement this without changing the time complexity. Although the previous section noted that, without knowing the position of the element in the heap, it would take linear time to search for it in order to re-order it, the trick here is that we can insert the new updated element (with the vertex and updated lower distance), and simply leave the old element (with the vertex and old higher distance) in the priority queue without removing it, thereby eliminating the need to find it.

Since we now leave multiple elements with the same vertex in the priority queue, in order to ensure we still only process a vertex's edges only once, we add a check when we retrieve an element from the priority queue, to check whether its distance is greater than the known minimum distance to that vertex. If this element is the most updated version for this vertex (i.e. the vertex's minimum distance has not been decreased since this element was added to the priority queue), then its distance must be equal to the current known minimum distance, since we only update the minimum distance in the decrease-key step. So if the element's distance is greater, we know that this is not the most updated version for this vertex -- i.e. we have already processed the edges for this vertex -- and we should ignore it.

The only downside to this strategy is that many old "garbage" elements will be left in the priority queue, increasing its size, and thus also increasing the time it takes to push and pop, as well as increasing the number of times we have to pop. However, we argue that the time complexity remains the same.

The main difference with the time complexity analysis for the previous algorithm is that here, we may add a vertex to the priority queue more than once. However, it is still true that the inner loop executes at most once for each directed edge. This is because in the outer loop, we added a check to ignore vertexes that we've already processed, so we will still only proceed down to the processing the edges at most once for each vertex. Therefore, the number of times that push is done on the priority queue (which happens at most once per iteration of the inner loop) is bounded by E, and the size of the priority queue is also bounded by E.

The number of times the outer loop executes (the number of times an element is popped from the priority queue) is bounded by E, and in each iteration, the popping operation takes time complexity O(log E). The number of times the inner loop executes is also bounded by E, and the pushing operation inside it also takes time complexity O(log E). So in total, the time complexity is O(E log E). But not that, for a simple graph, E < V^2, so log E < 2 log V = O(log V). So O(E log E) can also be written as O(E log V), which is the same as for the preceding algorithm.

#include <iostream>
#include <vector>
#include <string>
#include <list>

#include <limits> // for numeric_limits

#include <queue>
#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::pair<weight_t, vertex_t> weight_vertex_pair_t;

void DijkstraComputePaths(vertex_t source,
std::vector<weight_t> &min_distance,
std::vector<vertex_t> &previous)
{
min_distance.clear();
min_distance.resize(n, max_weight);
min_distance[source] = 0;
previous.clear();
previous.resize(n, -1);
// we use greater instead of less to turn max-heap into min-heap
std::priority_queue<weight_vertex_pair_t,
std::vector<weight_vertex_pair_t>,
std::greater<weight_vertex_pair_t> > vertex_queue;
vertex_queue.push(std::make_pair(min_distance[source], source));

while (!vertex_queue.empty())
{
weight_t dist = vertex_queue.top().first;
vertex_t u = vertex_queue.top().second;
vertex_queue.pop();

// Because we leave old copies of the vertex in the priority queue
// (with outdated higher distances), we need to ignore it when we come
// across it again, by checking its distance against the minimum distance
if (dist > min_distance[u])
continue;

// Visit each edge exiting 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]) {
min_distance[v] = distance_through_u;
previous[v] = u;
vertex_queue.push(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
// 0 = a
// 1 = b
// 2 = c
// 3 = d
// 4 = e
// 5 = f

std::vector<weight_t> min_distance;
std::vector<vertex_t> previous;
std::cout << "Distance from 0 to 4: " << min_distance << 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;
}

C#

{{works with|C sharp|7}}

using static System.Linq.Enumerable;
using static System.String;
using static System.Console;
using System.Collections.Generic;
using System;
using EdgeList = System.Collections.Generic.List<(int node, double weight)>;

public static class Dijkstra
{
public static void Main() {
Graph graph = new Graph(6);
Func<char, int> id = c => c - 'a';
Func<int , char> name = i => (char)(i + 'a');
foreach (var (start, end, cost) in 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),
}) {
}

var path = graph.FindPath(id('a'));
for (int d = id('b'); d <= id('f'); d++) {
WriteLine(Join(" -> ", Path(id('a'), d).Select(p => \$"{name(p.node)}({p.distance})").Reverse()));
}

IEnumerable<(double distance, int node)> Path(int start, int destination) {
yield return (path[destination].distance, destination);
for (int i = destination; i != start; i = path[i].prev) {
yield return (path[path[i].prev].distance, path[i].prev);
}
}
}

}

sealed class Graph
{

public Graph(int vertexCount) => adjacency = Range(0, vertexCount).Select(v => new EdgeList()).ToList();

public bool HasEdge(int s, int e) => adjacency[s].Any(p => p.node == e);
public bool RemoveEdge(int s, int e) => adjacency[s].RemoveAll(p => p.node == e) > 0;

public bool AddEdge(int s, int e, double weight) {
if (HasEdge(s, e)) return false;
return true;
}

public (double distance, int prev)[] FindPath(int start) {
var info = Range(0, adjacency.Count).Select(i => (distance: double.PositiveInfinity, prev: i)).ToArray();
info[start].distance = 0;

var heap = new Heap<(int node, double distance)>((a, b) => a.distance.CompareTo(b.distance));
heap.Push((start, 0));
while (heap.Count > 0) {
var current = heap.Pop();
if (visited[current.node]) continue;
for (int n = 0; n < edges.Count; n++) {
int v = edges[n].node;
if (visited[v]) continue;
double alt = info[current.node].distance + edges[n].weight;
if (alt < info[v].distance) {
info[v] = (alt, current.node);
heap.Push((v, alt));
}
}
visited[current.node] = true;
}
return info;
}

}

sealed class Heap<T>
{
private readonly List<T> list = new List<T> { default };

public Heap() : this(default(IComparer<T>)) { }

public Heap(IComparer<T> comparer) {
this.comparer = comparer ?? Comparer<T>.Default;
}

public Heap(Comparison<T> comparison) : this(Comparer<T>.Create(comparison)) { }

public int Count => list.Count - 1;

public void Push(T element) {
SiftUp(list.Count - 1);
}

public T Pop() {
T result = list;
list = list[list.Count - 1];
list.RemoveAt(list.Count - 1);
SiftDown(1);
return result;
}

private static int Parent(int i) => i / 2;
private static int Left(int i) => i * 2;
private static int Right(int i) => i * 2 + 1;

private void SiftUp(int i) {
while (i > 1) {
int parent = Parent(i);
if (comparer.Compare(list[i], list[parent]) > 0) return;
(list[parent], list[i]) = (list[i], list[parent]);
i = parent;
}
}

private void SiftDown(int i) {
for (int left = Left(i); left < list.Count; left = Left(i)) {
int smallest = comparer.Compare(list[left], list[i]) <= 0 ? left : i;
int right = Right(i);
if (right < list.Count && comparer.Compare(list[right], list[smallest]) <= 0) smallest = right;
if (smallest == i) return;
(list[i], list[smallest]) = (list[smallest], list[i]);
i = smallest;
}
}

}

{{out}}

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

Clojure

; '''Priority Queue'''
(require '[clojure.data.priority-map :refer [priority-map priority-map-keyfn]])

; '''Modification of Djikstra''' [[Media:https://www.ummels.de/2014/06/08/dijkstra-in-clojure/]]
(defn map-vals [m f]
(into {} (for [[k v] m]
[k (f v)])))

(defn remove-keys [m pred]
(select-keys m (filter (complement pred) (keys m))))

(defn min2 [v1 v2]
(if (< (first v1) (first v2))
v1
v2))

(defn dijkstra
"Computes single-source shortest path distances in a directed graph.

Given a node n, (graph n) should return a map with the successors of n
as keys and their (non-negative) distance from n as vals.

Returns a map from nodes to their distance from start."
[start graph]
(loop [q (priority-map-keyfn first start [0 nil]),
r {}]
(if-let [[v [d u]] (peek q)]
(let [dist (-> (graph v)
(remove-keys r)
(map-vals (fn [cost] (let [new-cost (+ d cost)] [new-cost v]))))]
(recur (merge-with min2 (pop q) dist) (assoc r v [d u])))
r)))

"Convert a list of nodes and a list of edges into an
adjacency list structure.  For example: with N [1 2 3],
E [[1 2] [2 3] [1 3]], the result is {1 [2 3], 2 , 3 []}"
[Nodes Edges]
(let [init-graph (reduce merge (map #(hash-map %1 {}) Nodes))]
(reduce #(merge-with merge %1 %2)
init-graph
(map #(hash-map (nth % 0) (hash-map (nth % 1) (nth % 2))) Edges))))

(defn path-to [goal dik]
(if (contains? dik goal)
(reverse (take-while identity (iterate (comp second dik) goal)))
nil))

(defn cost-to [goal dik]
(if (contains? dik goal)
(first (dik goal))
-1))
----
; '''Test'''

(def nodes ["a", "b", "c", "d", "e", "f"])
(def edges [["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]])
----
; Create Graph
; Dijstra from "a" to all other nodes
(def dij (dijkstra "a" g))

; '''Show path to "e"'''
(println (path-to "e" dij))

; '''Cost to "e""'''
(println (cost-to "e" dij))

{{Output}}

(a c d e)
26

Common Lisp

(defparameter *w* '((a (a b . 7) (a c . 9) (a f . 14))
(b (b c . 10) (b d . 15))
(c (c d . 11) (c f . 2))
(d (d e . 6))
(e (e f . 9))))

(defvar *r* nil)

(defun dijkstra-short-path (i g)
(setf *r* nil) (paths i g 0 `(,i))
(car (sort *r* #'< :key #'cadr)))

(defun paths (c g z v)
(if (eql c g) (push `(,(reverse v) ,z) *r*)
(loop for a in (nodes c) for b = (cadr a) do
(unless (member b v)
(paths b g (+ (cddr a) z) (cons b v))))))

(defun nodes (c)
(sort (cdr (assoc c *w*)) #'< :key #'cddr))

{{out}}

> (dijkstra-short-path 'a 'e)
((A C D E) 26)

(defvar *r* nil)

(defun dijkstra-short-paths (z w)
(loop for (a b) in (loop for v on z nconc
(loop for e in (cdr v)
collect `(,(car v) ,e)))
do (setf *r* nil) (paths w a b 0 `(,a))
(format t "~{Path: ~A  Distance: ~A~}~%"
(car (sort *r* #'< :key #'cadr)))))

(defun paths (w c g z v)
(if (eql c g) (push `(,(reverse v) ,z) *r*)
(loop for a in (sort (cdr (assoc c w)) #'< :key #'cddr)
for b = (cadr a) do (unless (member b v)
(paths w b g (+ (cddr a) z)
(cons b v))))))

{{out}}

> (dijkstra-short-paths
'(a b c d e f)
'((a (a b . 7) (a c . 9) (a f . 14))
(b (b c . 10) (b d . 15))
(c (c d . 11) (c f . 2))
(d (d e . 6))
(e (e f . 9))))
Path: (A B)  Distance: 7
Path: (A C)  Distance: 9
Path: (A C D)  Distance: 20
Path: (A C D E)  Distance: 26
Path: (A C F)  Distance: 11
Path: (B C)  Distance: 10
Path: (B D)  Distance: 15
Path: (B D E)  Distance: 21
Path: (B C F)  Distance: 12
Path: (C D)  Distance: 11
Path: (C D E)  Distance: 17
Path: (C F)  Distance: 2
Path: (D E)  Distance: 6
Path: (D E F)  Distance: 15
Path: (E F)  Distance: 9
NIL

D

{{trans|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;

struct Neighbor {
Vertex target;
Weight weight;
}

Weight[Vertex] minDistance;
Vertex[Vertex] previous;

minDistance[v] = Weight.max;
foreach(n; neighs) minDistance[n.target] = Weight.max;
}

minDistance[source] = 0;
auto vertexQueue = redBlackTree(tuple(minDistance[source], source));

foreach(_, u; vertexQueue){
if (u == target)
break;

// Visit each edge exiting u.
const v = n.target;
const distanceThroughU = minDistance[u] + n.weight;
if(distanceThroughU < minDistance[v]){
vertexQueue.removeKey(tuple(minDistance[v], v));
minDistance[v] = distanceThroughU;
previous[v] = u;
vertexQueue.insert(tuple(minDistance[v], v));
}
}
}

return tuple(minDistance, previous);
}

pure dijkstraGetShortestPathTo(Vertex v, Vertex[Vertex] previous){
Vertex[] 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)];

foreach (immutable arc; arcs) {
// Add this if you want an undirected graph:
}

const minDist_prev = dijkstraComputePaths("a", "e", adj);
const minDistance = minDist_prev;
const previous = minDist_prev;

writeln(`Distance from "a" to "e": `, minDistance["e"]);
writeln("Path: ", dijkstraGetShortestPathTo("e", previous));
}

{{out}}

Distance from "a" to "e": 26
Path: ["a", "c", "d", "e"]

Erlang

-module(dijkstra).
-include_lib("eunit/include/eunit.hrl").
-export([dijkstrafy/3]).

% just hide away recursion so we have a nice interface
dijkstrafy(Graph, Start, End) when is_map(Graph) ->
shortest_path(Graph, [{0, [Start]}], End, #{}).

shortest_path(_Graph, [], _End, _Visited) ->
% if we're not going anywhere, it's time to start going back
{0, []};
shortest_path(_Graph, [{Cost, [End | _] = Path} | _ ], End, _Visited) ->
% this is the base case, and finally returns the distance and the path
{Cost, lists:reverse(Path)};
shortest_path(Graph, [{Cost, [Node | _ ] = Path} | Routes], End, Visited) ->
% this is the recursive case.
% here we build a list of new "unvisited" routes, where the stucture is
% a tuple of cost, then a list of paths taken to get to that cost from the "Start"
NewRoutes = [{Cost + NewCost, [NewNode | Path]}
|| {NewCost, NewNode} <- maps:get(Node, Graph),
not maps:get(NewNode, Visited, false)],
shortest_path(
Graph,
% add the routes we ripped off earlier onto the new routes
% that we want to visit. sort the list of routes to get the
% shortest routes (lowest cost) at the beginning.
% Erlangs sort is already good enough, and it will sort the
% tuples by the number at the beginning of each (the cost).
lists:sort(NewRoutes ++ Routes),
End,
Visited#{Node => true}
).

basic_test() ->
Graph = #{
a => [{7,b},{9,c},{14,f}],
b => [{7,a},{10,c},{15,d}],
c => [{10,b},{9,c},{11,d},{2,f}],
d => [{15,b},{6,e},{11,c}],
e => [{9,f},{6,d}],
f => [{14,f},{2,c},{9,e}]
},
{Cost, Path}   = dijkstrafy(Graph, a, e),
{20,[a,c,f,e]} = {Cost, Path},
io:format(user, "The total cost was ~p and the path was: ", [Cost]),
io:format(user, "~w~n", [Path]).

{{out}}

\$ ./rebar3 eunit
===> Verifying dependencies...
===> Compiling dijkstra
===> Performing EUnit tests...
The total cost was 20 and the path was: [a,c,f,e]
Test passed.

//Dijkstra's algorithm: Nigel Galloway, August 5th., 2018
[<CustomEquality;CustomComparison>]
type Dijkstra<'N,'G when 'G:comparison>={toN:'N;cost:Option<'G>;fromN:'N}
override g.Equals n =match n with| :? Dijkstra<'N,'G> as n->n.cost=g.cost|_->false
override g.GetHashCode() = hash g.cost
interface System.IComparable with
member n.CompareTo g =
match g with
| :? Dijkstra<'N,'G> as n when n.cost=None -> (-1)
| :? Dijkstra<'N,'G>      when n.cost=None -> 1
| :? Dijkstra<'N,'G> as g                  -> compare n.cost g.cost
| _-> invalidArg "n" "expecting type Dijkstra<'N,'G>"
let inline Dijkstra N G y =
let rec fN l f=
if List.isEmpty l then f
else let n=List.min l
if n.cost=None then f else
fN(l|>List.choose(fun n'->if n'.toN=n.toN then None else match n.cost,n'.cost,Map.tryFind (n.toN,n'.toN) G with
|Some g,None,Some wg                ->Some {toN=n'.toN;cost=Some(g+wg);fromN=n.toN}
|Some g,Some g',Some wg when g+wg<g'->Some {toN=n'.toN;cost=Some(g+wg);fromN=n.toN}
|_                                  ->Some n'))((n.fromN,n.toN)::f)
let r = fN (N|>List.map(fun n->{toN=n;cost=(Map.tryFind(y,n)G);fromN=y})) []
(fun n->let rec fN z l=match List.tryFind(fun (_,g)->g=z) r with
|Some(n',g') when y=n'->Some(n'::g'::l)
|Some(n',g')          ->fN n' (g'::l)
|_                    ->None
fN n [])

type Node= |A|B|C|D|E|F
let G=Map[((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)]
let paths=Dijkstra [B;C;D;E;F] G A
printfn "%A" (paths E)
printfn "%A" (paths F)

{{out}}

Some [A; C; D; E]
Some [A; C; F]

Go

package main

import (
"container/heap"
"fmt"
)

// A PriorityQueue implements heap.Interface and holds Items.
type PriorityQueue struct {
items []Vertex
// value to index
m map[Vertex]int
// value to priority
pr map[Vertex]int
}

func (pq *PriorityQueue) Len() int           { return len(pq.items) }
func (pq *PriorityQueue) Less(i, j int) bool { return pq.pr[pq.items[i]] < pq.pr[pq.items[j]] }
func (pq *PriorityQueue) Swap(i, j int) {
pq.items[i], pq.items[j] = pq.items[j], pq.items[i]
pq.m[pq.items[i]] = i
pq.m[pq.items[j]] = j
}
func (pq *PriorityQueue) Push(x interface{}) {
n := len(pq.items)
item := x.(Vertex)
pq.m[item] = n
pq.items = append(pq.items, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := pq.items
n := len(old)
item := old[n-1]
pq.m[item] = -1
pq.items = old[0 : n-1]
return item
}

// update modifies the priority of an item in the queue.
func (pq *PriorityQueue) update(item Vertex, priority int) {
pq.pr[item] = priority
heap.Fix(pq, pq.m[item])
}
func (pq *PriorityQueue) addWithPriority(item Vertex, priority int) {
heap.Push(pq, item)
pq.update(item, priority)
}

const (
Infinity      = int(^uint(0) >> 1)
Uninitialized = -1
)

func Dijkstra(g Graph, source Vertex) (dist map[Vertex]int, prev map[Vertex]Vertex) {
dist = make(map[Vertex]int)
prev = make(map[Vertex]Vertex)
sid := source
dist[sid] = 0
q := &PriorityQueue{[]Vertex{}, make(map[Vertex]int), make(map[Vertex]int)}
for _, v := range g.Vertices() {
if v != sid {
dist[v] = Infinity
}
prev[v] = Uninitialized
}
for len(q.items) != 0 {
u := heap.Pop(q).(Vertex)
for _, v := range g.Neighbors(u) {
alt := dist[u] + g.Weight(u, v)
if alt < dist[v] {
dist[v] = alt
prev[v] = u
q.update(v, alt)
}
}
}
return dist, prev
}

// A Graph is the interface implemented by graphs that
// this algorithm can run on.
type Graph interface {
Vertices() []Vertex
Neighbors(v Vertex) []Vertex
Weight(u, v Vertex) int
}

// Nonnegative integer ID of vertex
type Vertex int

// sg is a graph of strings that satisfies the Graph interface.
type sg struct {
ids   map[string]Vertex
names map[Vertex]string
edges map[Vertex]map[Vertex]int
}

func newsg(ids map[string]Vertex) sg {
g := sg{ids: ids}
g.names = make(map[Vertex]string)
for k, v := range ids {
g.names[v] = k
}
g.edges = make(map[Vertex]map[Vertex]int)
return g
}
func (g sg) edge(u, v string, w int) {
if _, ok := g.edges[g.ids[u]]; !ok {
g.edges[g.ids[u]] = make(map[Vertex]int)
}
g.edges[g.ids[u]][g.ids[v]] = w
}
func (g sg) path(v Vertex, prev map[Vertex]Vertex) (s string) {
s = g.names[v]
for prev[v] >= 0 {
v = prev[v]
s = g.names[v] + s
}
return s
}
func (g sg) Vertices() (vs []Vertex) {
for _, v := range g.ids {
vs = append(vs, v)
}
return vs
}
func (g sg) Neighbors(u Vertex) (vs []Vertex) {
for v := range g.edges[u] {
vs = append(vs, v)
}
return vs
}
func (g sg) Weight(u, v Vertex) int { return g.edges[u][v] }

func main() {
g := newsg(map[string]Vertex{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
"f": 6,
})
g.edge("a", "b", 7)
g.edge("a", "c", 9)
g.edge("a", "f", 14)
g.edge("b", "c", 10)
g.edge("b", "d", 15)
g.edge("c", "d", 11)
g.edge("c", "f", 2)
g.edge("d", "e", 6)
g.edge("e", "f", 9)

dist, prev := Dijkstra(g, g.ids["a"])
fmt.Printf("Distance to %s: %d, Path: %s\n", "e", dist[g.ids["e"]], g.path(g.ids["e"], prev))
fmt.Printf("Distance to %s: %d, Path: %s\n", "f", dist[g.ids["f"]], g.path(g.ids["f"], prev))
}

{{out}}

Distance to e: 26, Path: acde
Distance to f: 11, Path: acf

{{trans|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 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
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)
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

Huginn

import Algorithms as algo;
import Mathematics as math;
import Text as text;

class Edge {
_to = none;
_name = none;
_cost = none;
constructor( to_, name_, cost_ ) {
_to = to_;
_name = name_;
_cost = real( cost_ );
}
to_string() {
return ( "{}<{}>".format( _name, _cost ) );
}
}

class Path {
_id = none;
_from = none;
_cost = none;
_names = none;
constructor( toName_, ids_, names_ ) {
_id = ids_[toName_];
_names = names_;
_cost = math.INFINITY;
}
less( other_ ) {
return ( _cost < other_._cost );
}
update( from_, cost_ ) {
_from = from_;
_cost = cost_;
}
to_string() {
return ( "{} via {} at cost {}".format( _names[_id], _from != none ? _names[_from] : none, _cost ) );
}
}

class Graph {
_neighbours = [];
_ids = {};
_names = [];
if ( name_ ∉ _ids ) {
_ids[name_] = size( _names );
_names.push( name_ );
}
}
add_edge( from_, to_, cost_ ) {
assert( ( from_ ∈ _ids ) && ( to_ ∈ _ids ) );
from = _ids[from_];
to = _ids[to_];
if ( from >= size( _neighbours ) ) {
_neighbours.resize( from + 1, [] );
}
_neighbours[from].push( Edge( to, to_, cost_ ) );
}
shortest_paths( from_ ) {
assert( from_ ∈ _ids );
from = _ids[from_];
paths = algo.materialize( algo.map( _names, @[_ids, _names]( name ) { Path( name, _ids, _names ); } ), list );
paths[from].update( none, 0.0 );
todo = algo.sorted( paths, @(x){-x._cost;} );
while ( size( todo ) > 0 ) {
node = todo[-1]._id;
todo.resize( size( todo ) - 1, none );
if ( node >= size( _neighbours ) ) {
continue;
}
neighbours = _neighbours[node];
for ( n : neighbours ) {
newCost = n._cost + paths[node]._cost;
if ( newCost < paths[n._to]._cost ) {
paths[n._to].update( node, newCost );
}
}
todo = algo.sorted( todo, @(x){-x._cost;} );
}
return ( paths );
}
path( paths_, to_ ) {
assert( to_ ∈ _ids );
to = _ids[to_];
p = [to_];
while ( paths_[to]._from != none ) {
to = paths_[to]._from;
p.push( _names[to] );
}
return ( algo.materialize( algo.reversed( p ), list ) );
}
to_string() {
s = "";
for ( i, n : algo.enumerate( _neighbours ) ) {
s += "{} -> {}\n".format( _names[i], n );
}
}
}

main() {
g = Graph();
confStr = input();
if ( confStr == none ) {
return ( 1 );
}
conf = algo.materialize( algo.map( text.split( confStr ), integer ), tuple );
assert( size( conf ) == 2 );
for ( _ : algo.range( conf ) ) {
line = input();
if ( line == none ) {
return ( 1 );
}
}
for ( _ : algo.range( conf ) ) {
line = input();
if ( line == none ) {
return ( 1 );
}
g.add_edge( algo.materialize( text.split( line.strip() ), tuple )... );
}
print( string( g ) );
paths = g.shortest_paths( "a" );
for ( p : paths ) {
print( "{}\n".format( p ) );
}
print( "{}\n".format( g.path( paths, "e" ) ) );
print( "{}\n".format( g.path( paths, "f" ) ) );
}

Sample run via:

cat ~/graph.g | ./dijkstra.hgn

, output:

a -> [b<7.0>, c<9.0>, f<14.0>]
b -> [c<10.0>, d<15.0>]
c -> [d<11.0>, f<2.0>]
d -> [e<6.0>]
e -> [f<9.0>]
a via none at cost 0.0
b via a at cost 7.0
c via a at cost 9.0
d via c at cost 20.0
e via d at cost 26.0
f via c at cost 11.0
[a, c, d, e]
[a, c, f]

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? ")
writes("What is the finish node? ")

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

J

parse_table=: ;:@:(LF&= [;._2 -.&CR)
mp=: \$:~ :(+/ .*)                       NB. matrix product
min=: <./                               NB. minimum

'LINK WEIGHT'=. , (0 _ ,. 2) <;.3 y
FRONTIER=. , < {. x
GOAL=. {: x
enumerate=. 2&([\)&.>
while. FRONTIER do.
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
NODES=: ~. , NAMED_LINKS                NB. vector of boxed names
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
)

J: Alternative Implementation

vertices=: ;:'a b c d e f'
edges=:|: ;:;._2]0 :0
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
)

shortest_path=:1 :0
:
NB. x: path endpoints, m: vertex labels, y: edges (starts,ends,:costs)
terminals=. m i. x
starts=. m i. 0{y
ends=.   m i. 1{y
tolls=.  _&".@> 2{y
C=. tolls (starts,&.>ends)}_\$~2##m
bestprice=. (<terminals){ (<. <./ .+/~)^:_ C
best=. i.0
if. _>bestprice do.
paths=. ,.{.terminals
goal=. {:terminals
costs=. ,0
while. #costs do.
next=. ({:paths){C
keep=. (_>next)*bestprice>:next+costs
rep=. +/"1 keep
paths=. (rep#"1 paths),(#m)|I.,keep
costs=. (rep#"1 costs)+keep #&, next
if. #j=. I. goal = {:paths do.
best=. best, (bestprice=j{costs)# <"1 j{|:paths
end.
toss=. <<<j,I.bestprice<:costs
paths=. toss {"1 paths
costs=. toss { costs
end.
end.
best {L:0 _ m
)

Example use:

(;:'a e') vertices shortest_path edges
┌─────────┐
│┌─┬─┬─┬─┐│
││a│c│d│e││
│└─┴─┴─┴─┘│
└─────────┘

This version finds all shortest paths, and for this example completes in two thirds the time of the other J implementation.

This algorithm first translates the graph representation to a cost connection matrix, with infinite cost for unconnected nodes. Then we use [[Floyd-Warshall_algorithm#J|a summing variation on transitive closure]] to find minimal connection costs for all nodes, and extract our best price from that. If our desired nodes are connected, we then search for paths which satisfy this best (minimal) price constraint: We repeatedly find all connections from our frontier, tracking path cost and discarding paths which have a cost which exceeds our best price. When a path reaches the end node, it is removed and remembered.

Java

Algorithm is derived from Wikipedia section 'Using a priority queue'. This implementation finds the single path from a source to all reachable vertices. Building the graph from a set of edges takes O(E log V) for each pass. Vertices are stored in a TreeSet (self-balancing binary search tree) instead of a PriorityQueue (a binary heap) in order to get O(log n) performance for removal of any element, not just the head. Decreasing the distance of a vertex is accomplished by removing it from the tree and later re-inserting it.

import java.io.*;
import java.util.*;

public class Dijkstra {
private static final Graph.Edge[] GRAPH = {
new Graph.Edge("a", "b", 7),
new Graph.Edge("a", "c", 9),
new Graph.Edge("a", "f", 14),
new Graph.Edge("b", "c", 10),
new Graph.Edge("b", "d", 15),
new Graph.Edge("c", "d", 11),
new Graph.Edge("c", "f", 2),
new Graph.Edge("d", "e", 6),
new Graph.Edge("e", "f", 9),
};
private static final String START = "a";
private static final String END = "e";

public static void main(String[] args) {
Graph g = new Graph(GRAPH);
g.dijkstra(START);
g.printPath(END);
//g.printAllPaths();
}
}

class Graph {
private final Map<String, Vertex> graph; // mapping of vertex names to Vertex objects, built from a set of Edges

/** One edge of the graph (only used by Graph constructor) */
public static class Edge {
public final String v1, v2;
public final int dist;
public Edge(String v1, String v2, int dist) {
this.v1 = v1;
this.v2 = v2;
this.dist = dist;
}
}

/** One vertex of the graph, complete with mappings to neighbouring vertices */
public static class Vertex implements Comparable<Vertex>{
public final String name;
public int dist = Integer.MAX_VALUE; // MAX_VALUE assumed to be infinity
public Vertex previous = null;
public final Map<Vertex, Integer> neighbours = new HashMap<>();

public Vertex(String name)
{
this.name = name;
}

private void printPath()
{
if (this == this.previous)
{
System.out.printf("%s", this.name);
}
else if (this.previous == null)
{
System.out.printf("%s(unreached)", this.name);
}
else
{
this.previous.printPath();
System.out.printf(" -> %s(%d)", this.name, this.dist);
}
}

public int compareTo(Vertex other)
{
if (dist == other.dist)
return name.compareTo(other.name);

return Integer.compare(dist, other.dist);
}

@Override public String toString()
{
return "(" + name + ", " + dist + ")";
}
}

/** Builds a graph from a set of edges */
public Graph(Edge[] edges) {
graph = new HashMap<>(edges.length);

//one pass to find all vertices
for (Edge e : edges) {
if (!graph.containsKey(e.v1)) graph.put(e.v1, new Vertex(e.v1));
if (!graph.containsKey(e.v2)) graph.put(e.v2, new Vertex(e.v2));
}

//another pass to set neighbouring vertices
for (Edge e : edges) {
graph.get(e.v1).neighbours.put(graph.get(e.v2), e.dist);
//graph.get(e.v2).neighbours.put(graph.get(e.v1), e.dist); // also do this for an undirected graph
}
}

/** Runs dijkstra using a specified source vertex */
public void dijkstra(String startName) {
if (!graph.containsKey(startName)) {
System.err.printf("Graph doesn't contain start vertex \"%s\"\n", startName);
return;
}
final Vertex source = graph.get(startName);
NavigableSet<Vertex> q = new TreeSet<>();

// set-up vertices
for (Vertex v : graph.values()) {
v.previous = v == source ? source : null;
v.dist = v == source ? 0 : Integer.MAX_VALUE;
}

dijkstra(q);
}

/** Implementation of dijkstra's algorithm using a binary heap. */
private void dijkstra(final NavigableSet<Vertex> q) {
Vertex u, v;
while (!q.isEmpty()) {

u = q.pollFirst(); // vertex with shortest distance (first iteration will return source)
if (u.dist == Integer.MAX_VALUE) break; // we can ignore u (and any other remaining vertices) since they are unreachable

//look at distances to each neighbour
for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) {
v = a.getKey(); //the neighbour in this iteration

final int alternateDist = u.dist + a.getValue();
if (alternateDist < v.dist) { // shorter path to neighbour found
q.remove(v);
v.dist = alternateDist;
v.previous = u;
}
}
}
}

/** Prints a path from the source to the specified vertex */
public void printPath(String endName) {
if (!graph.containsKey(endName)) {
System.err.printf("Graph doesn't contain end vertex \"%s\"\n", endName);
return;
}

graph.get(endName).printPath();
System.out.println();
}
/** Prints the path from the source to every vertex (output order is not guaranteed) */
public void printAllPaths() {
for (Vertex v : graph.values()) {
v.printPath();
System.out.println();
}
}
}

{{out}}

a -> c(9) -> d(20) -> e(26)

Javascript

Using the [[wp:Dijkstra's_algorithm#Pseudocode]]

const dijkstra = (edges,source,target) => {
const Q = new Set(),
prev = {},
dist = {},

const vertex_with_min_dist = (Q,dist) => {
let min_distance = Infinity,
u = null

for (let v of Q) {
if (dist[v] < min_distance) {
min_distance = dist[v]
u = v
}
}
return u
}

for (let i=0;i<edges.length;i++) {
let v1 = edges[i],
v2 = edges[i],
len = edges[i]

dist[v1] = Infinity
dist[v2] = Infinity

}

dist[source] = 0

while (Q.size) {
let u = vertex_with_min_dist(Q,dist),
neighbors = Object.keys(adj[u]).filter(v=>Q.has(v)) //Neighbor still in Q

Q.delete(u)

if (u===target) break //Break when the target has been found

for (let v of neighbors) {
let alt = dist[u] + adj[u][v]
if (alt < dist[v]) {
dist[v] = alt
prev[v] = u
}
}
}

{
let u = target,
S = [u],
len = 0

while (prev[u] !== undefined) {
S.unshift(prev[u])
u = prev[u]
}
return [S,len]
}
}

//Testing algorithm
let graph = []
graph.push(["a", "b", 7])
graph.push(["a", "c", 9])
graph.push(["a", "f", 14])
graph.push(["b", "c", 10])
graph.push(["b", "d", 15])
graph.push(["c", "d", 11])
graph.push(["c", "f", 2])
graph.push(["d", "e", 6])
graph.push(["e", "f", 9])

let [path,length] = dijkstra(graph, "a", "e");
console.log(path) //[ 'a', 'c', 'f', 'e' ]
console.log(length) //20

Julia

{{works with|Julia|0.6}}

struct Digraph{T <: Real,U}
edges::Dict{Tuple{U,U},T}
verts::Set{U}
end

function Digraph(edges::Vector{Tuple{U,U,T}}) where {T <: Real,U}
vnames = Set{U}(v for edge in edges for v in edge[1:2])
adjmat = Dict((edge, edge) => edge for edge in edges)
end

vertices(g::Digraph) = g.verts
edges(g::Digraph)    = g.edges

neighbours(g::Digraph, v) = Set((b, c) for ((a, b), c) in edges(g) if a == v)

function dijkstrapath(g::Digraph{T,U}, source::U, dest::U) where {T, U}
@assert source vertices(g) "\$source is not a vertex in the graph"

# Easy case
if source == dest return [source], 0 end
# Initialize variables
inf  = typemax(T)
dist = Dict(v => inf for v in vertices(g))
prev = Dict(v => v   for v in vertices(g))
dist[source] = 0
Q = copy(vertices(g))
neigh = Dict(v => neighbours(g, v) for v in vertices(g))

# Main loop
while !isempty(Q)
u = reduce((x, y) -> dist[x] < dist[y] ? x : y, Q)
pop!(Q, u)
if dist[u] == inf || u == dest break end
for (v, cost) in neigh[u]
alt = dist[u] + cost
if alt < dist[v]
dist[v] = alt
prev[v] = u
end
end
end

# Return path
rst, cost = U[], dist[dest]
if prev[dest] == dest
return rst, cost
else
while dest != source
unshift!(rst, dest)
dest = prev[dest]
end
unshift!(rst, dest)
return rst, cost
end
end

# testgraph = [("a", "b", 1), ("b", "e", 2), ("a", "e", 4)]
testgraph = [("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)]
g = Digraph(testgraph)
src, dst = "a", "e"
path, cost = dijkstrapath(g, src, dst)
println("Shortest path from \$src to \$dst: ", isempty(path) ? "no possible path" : join(path, " → "), " (cost \$cost)")

# Print all possible paths
@printf("\n%4s | %3s | %s\n", "src", "dst", "path")
@printf("----------------\n")
for src in vertices(g), dst in vertices(g)
path, cost = dijkstrapath(g, src, dst)
@printf("%4s | %3s | %s\n", src, dst, isempty(path) ? "no possible path" : join(path, " → ") * " (\$cost)")
end

{{out}}

Shortest path from a to e: a → c → d → e (cost 26)

src | dst | path
----------------
f |   f | f (0)
f |   c | no possible path
f |   e | no possible path
f |   b | no possible path
f |   a | no possible path
f |   d | no possible path
c |   f | c → f (2)
c |   c | c (0)
c |   e | c → d → e (17)
c |   b | no possible path
c |   a | no possible path
c |   d | c → d (11)
e |   f | e → f (9)
e |   c | no possible path
e |   e | e (0)
e |   b | no possible path
e |   a | no possible path
e |   d | no possible path
b |   f | b → c → f (12)
b |   c | b → c (10)
b |   e | b → d → e (21)
b |   b | b (0)
b |   a | no possible path
b |   d | b → d (15)
a |   f | a → c → f (11)
a |   c | a → c (9)
a |   e | a → c → d → e (26)
a |   b | a → b (7)
a |   a | a (0)
a |   d | a → c → d (20)
d |   f | d → e → f (15)
d |   c | no possible path
d |   e | d → e (6)
d |   b | no possible path
d |   a | no possible path
d |   d | d (0)

Kotlin

{{trans|Java}}

// version 1.1.51

import java.util.TreeSet

class Edge(val v1: String, val v2: String, val dist: Int)

/** One vertex of the graph, complete with mappings to neighbouring vertices */
class Vertex(val name: String) : Comparable<Vertex> {

var dist = Int.MAX_VALUE  // MAX_VALUE assumed to be infinity
var previous: Vertex? = null
val neighbours = HashMap<Vertex, Int>()

fun printPath() {
if (this == previous) {
print(name)
}
else if (previous == null) {
print("\$name(unreached)")
}
else {
previous!!.printPath()
print(" -> \$name(\$dist)")
}
}

override fun compareTo(other: Vertex): Int {
if (dist == other.dist) return name.compareTo(other.name)
return dist.compareTo(other.dist)
}

override fun toString() = "(\$name, \$dist)"
}

class Graph(
val edges: List<Edge>,
val directed: Boolean,
val showAllPaths: Boolean = false
) {
// mapping of vertex names to Vertex objects, built from a set of Edges
private val graph = HashMap<String, Vertex>(edges.size)

init {
// one pass to find all vertices
for (e in edges) {
if (!graph.containsKey(e.v1)) graph.put(e.v1, Vertex(e.v1))
if (!graph.containsKey(e.v2)) graph.put(e.v2, Vertex(e.v2))
}

// another pass to set neighbouring vertices
for (e in edges) {
graph[e.v1]!!.neighbours.put(graph[e.v2]!!, e.dist)
// also do this for an undirected graph if applicable
if (!directed) graph[e.v2]!!.neighbours.put(graph[e.v1]!!, e.dist)
}
}

/** Runs dijkstra using a specified source vertex */
fun dijkstra(startName: String) {
if (!graph.containsKey(startName)) {
println("Graph doesn't contain start vertex '\$startName'")
return
}
val source = graph[startName]
val q = TreeSet<Vertex>()

// set-up vertices
for (v in graph.values) {
v.previous = if (v == source) source else null
v.dist = if (v == source)  0 else Int.MAX_VALUE
}

dijkstra(q)
}

/** Implementation of dijkstra's algorithm using a binary heap */
private fun dijkstra(q: TreeSet<Vertex>) {
while (!q.isEmpty()) {
// vertex with shortest distance (first iteration will return source)
val u = q.pollFirst()
// if distance is infinite we can ignore 'u' (and any other remaining vertices)
// since they are unreachable
if (u.dist == Int.MAX_VALUE) break

//look at distances to each neighbour
for (a in u.neighbours) {
val v = a.key // the neighbour in this iteration

val alternateDist = u.dist + a.value
if (alternateDist < v.dist) { // shorter path to neighbour found
q.remove(v)
v.dist = alternateDist
v.previous = u
}
}
}
}

/** Prints a path from the source to the specified vertex */
fun printPath(endName: String) {
if (!graph.containsKey(endName)) {
println("Graph doesn't contain end vertex '\$endName'")
return
}
print(if (directed) "Directed   : " else "Undirected : ")
graph[endName]!!.printPath()
println()
if (showAllPaths) printAllPaths() else println()
}

/** Prints the path from the source to every vertex (output order is not guaranteed) */
private fun printAllPaths() {
for (v in graph.values) {
v.printPath()
println()
}
println()
}
}

val GRAPH = listOf(
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)
)

const val START = "a"
const val END = "e"

fun main(args: Array<String>) {
with (Graph(GRAPH, true)) {   // directed
dijkstra(START)
printPath(END)
}
with (Graph(GRAPH, false)) {  // undirected
dijkstra(START)
printPath(END)
}
}

{{out}}

Directed   : a -> c(9) -> d(20) -> e(26)

Undirected : a -> c(9) -> f(11) -> e(20)

Lua

Hopefully the variable names here make the process as clear as possible...

-- Graph definition
local edges = {
a = {b = 7, c = 9, f = 14},
b = {c = 10, d = 15},
c = {d = 11, f = 2},
d = {e = 6},
e = {f = 9}
}

-- Fill in paths in the opposite direction to the stated edges
function complete (graph)
for node, edges in pairs(graph) do
for edge, distance in pairs(edges) do
if not graph[edge] then graph[edge] = {} end
graph[edge][node] = distance
end
end
end

-- Create path string from table of previous nodes
local path, nextStep = destination, trail[destination]
while nextStep do
path = nextStep .. " " .. path
nextStep = trail[nextStep]
end
return path
end

-- Find the shortest path between the current and destination nodes
function dijkstra (graph, current, destination, directed)
if not directed then complete(graph) end
local unvisited, distanceTo, trail = {}, {}, {}
local nearest, nextNode, tentative
for node, edgeDists in pairs(graph) do
if node == current then
distanceTo[node] = 0
trail[current] = false
else
distanceTo[node] = math.huge
unvisited[node] = true
end
end
repeat
nearest = math.huge
for neighbour, pathDist in pairs(graph[current]) do
if unvisited[neighbour] then
tentative = distanceTo[current] + pathDist
if tentative < distanceTo[neighbour] then
distanceTo[neighbour] = tentative
trail[neighbour] = current
end
if tentative < nearest then
nearest = tentative
nextNode = neighbour
end
end
end
unvisited[current] = false
current = nextNode
until unvisited[destination] == false or nearest == math.huge
return distanceTo[destination], follow(trail, destination)
end

-- Main procedure
print("Directed:", dijkstra(edges, "a", "e", true))
print("Undirected:", dijkstra(edges, "a", "e", false))

{{out}}

Directed:       26      a c d e
Undirected:     20      a c f e

M2000 Interpreter

Module Dijkstra`s_algorithm {
const max_number=1.E+306
GetArr=lambda (n, val)->{
dim d(n)=val
=d()
}
term=("",0)
Edges=(("a", ("b",7),("c",9),("f",14)),("b",("c",10),("d",15)),("c",("d",11),("f",2)),("d",("e",6)),("e",("f", 9)),("f",term))
Document Doc\$="Graph:"+{
}
ShowGraph()
Doc\$="Paths"+{
}
Print "Paths"
For from_here=0 to 5
pa=GetArr(len(Edges), -1)
d=GetArr(len(Edges), max_number)
Inventory S=1,2,3,4,5,6
return d, from_here:=0
RemoveMin=Lambda S, d, max_number-> {
ss=each(S)
min=max_number
p=0
while ss
val=d#val(eval(S,ss^)-1)
if min>val then let min=val : p=ss^
end while
=s(p!)  ' use p as index not key
Delete S, eval(s,p)
}
Show_Distance_and_Path\$=lambda\$ d, pa, from_here, max_number (n) -> {
ret1\$=chr\$(from_here+asc("a"))+" to "+chr\$(n+asc("a"))
if d#val(n) =max_number then =ret1\$+ "     No Path" :exit
let ret\$="", mm=n, m=n
repeat
n=m
ret\$+=chr\$(asc("a")+n)
m=pa#val(n)
until  from_here=n
=ret1\$+format\$("{0::-4} {1}",d#val(mm),strrev\$(ret\$))
}
while len(s)>0
u=RemoveMin()
rem Print u, chr\$(u-1+asc("a"))
Relaxed()
end while
For i=0 to len(d)-1
line\$=Show_Distance_and_Path\$(i)
Print line\$
doc\$=line\$+{
}
next
next
Clipboard Doc\$
End
Sub Relaxed()
local vertex=Edges#val(u-1), i
local e=Len(vertex)-1, edge=(,), val
for i=1 to e
edge=vertex#val(i)
if edge#val\$(0)<>"" then
val=Asc(edge#val\$(0))-Asc("a")
if d#val(val)>edge#val(1)+d#val(u-1) then  return d, val:=edge#val(1)+d#val(u-1) : Return Pa, val:=u-1
end if
next
end sub
Sub ShowGraph()
Print "Graph"
local i
for i=1 to len(Edges)
show_edges(i)
next
end sub
Sub show_edges(n)
n--
local vertex=Edges#val(n), line\$
local e=each(vertex 2 to end), v2=(,)
While e
v2=array(e)
line\$=vertex#val\$(0)+if\$(v2#val\$(0)<>""->"->"+v2#val\$(0)+format\$(" {0::-2}",v2#val(1)),"")
Print line\$
Doc\$=line\$+{
}
end while
end sub
}
Dijkstra`s_algorithm

{{out}}

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
f
Paths
a to a   0 a
a to b   7 ab
a to c   9 ac
a to d  20 acd
a to e  26 acde
a to f  11 acf
b to a     No Path
b to b   0 b
b to c  10 bc
b to d  15 bd
b to e  21 bde
b to f  12 bcf
c to a     No Path
c to b     No Path
c to c   0 c
c to d  11 cd
c to e  17 cde
c to f   2 cf
d to a     No Path
d to b     No Path
d to c     No Path
d to d   0 d
d to e   6 de
d to f  15 def
e to a     No Path
e to b     No Path
e to c     No Path
e to d     No Path
e to e   0 e
e to f   9 ef
f to a     No Path
f to b     No Path
f to c     No Path
f to d     No Path
f to e     No Path
f to f   0 f