Dijkstra's algorithm

From Rosetta Code
Task
Dijkstra's algorithm
You are encouraged to solve this task according to the task description, using any language you may know.
This task has been clarified. Its programming examples are in need of review to ensure that they still fit the requirements of the task.


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 non-negative 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.


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 routing protocols, most notably:

  •   IS-IS   (Intermediate System to Intermediate System)   and
  •   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 ]


Task
  1. Implement a version of Dijkstra's algorithm that outputs a set of edges depicting the shortest path to each reachable node from an origin.
  2. Run your program with the following directed graph starting at node   a.
  3. Write a program which interprets the output from the above and use it to output the shortest path from node   a   to nodes   e   and f.
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.


See also



11l

Translation of: Python
T Edge = (String start, String end, Int cost)

T Graph
   [Edge] edges
   Set[String] vertices

   F (edges)
      .edges = edges.map((s, e, c) -> Edge(s, e, c))
      .vertices = Set(.edges.map(e -> e.start)).union(Set(.edges.map(e -> e.end)))

   F dijkstra(source, dest)
      assert(source C .vertices)
      V dist = Dict(.vertices, vertex -> (vertex, Float.infinity))
      V previous = Dict(.vertices, vertex -> (vertex, ‘’))
      dist[source] = 0
      V q = copy(.vertices)
      V neighbours = Dict(.vertices, vertex -> (vertex, [(String, Int)]()))
      L(start, end, cost) .edges
         neighbours[start].append((end, cost))

      L !q.empty
         V u = min(q, key' vertex -> @dist[vertex])
         q.remove(u)
         I dist[u] == Float.infinity | u == dest
            L.break
         L(v, cost) neighbours[u]
            V alt = dist[u] + cost
            I alt < dist[v]
               dist[v] = alt
               previous[v] = u

      Deque[String] s
      V u = dest
      L previous[u] != ‘’
         s.append_left(u)
         u = previous[u]
      s.append_left(u)
      R s

V 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)])
print(graph.dijkstra(‘a’, ‘e’))
Output:
Deque([a, c, d, e])

Ada

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.

private with Ada.Containers.Ordered_Maps;
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;
with Ada.Containers.Ordered_Sets;
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 Ada.Text_IO; use Ada.Text_IO;
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;
Output:
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 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

Arturo

Translation of: Nim
define :graph [vertices, neighbours][]

initGraph: function [edges][
    vs: []
    ns: #[]
    loop edges 'e [
        [src, dst, cost]: e
        vs: sort unique append vs src
        vs: sort unique append vs dst
        if not? key? ns src -> ns\[src]: []

        ns\[src]: ns\[src] ++ @[@[dst, cost]]
    ]
    to :graph @[vs ns]
]

Inf: 1234567890

dijkstraPath: function [gr, fst, lst][
    dist: #[]
    prev: #[]
    result: new []
    notSeen: new gr\vertices
    loop gr\vertices 'vertex ->
        dist\[vertex]: Inf

    dist\[fst]: 0

    while [0 < size notSeen][
        vertex1: ""
        mindist: Inf
        loop notSeen 'vertex [
            if dist\[vertex] < mindist [
                vertex1: vertex
                mindist: dist\[vertex]
            ]
        ]
        if vertex1 = lst -> break
        'notSeen -- vertex1

        if key? gr\neighbours vertex1 [
            loop gr\neighbours\[vertex1] 'v [
                [vertex2, cost]: v

                if contains? notSeen vertex2 [
                    altdist: dist\[vertex1] + cost
                    if altdist < dist\[vertex2][
                        dist\[vertex2]: altdist
                        prev\[vertex2]: vertex1
                    ]
                ]
            ]
        ]
    ]

    vertex: lst
    while [not? empty? vertex][
        'result ++ vertex
        vertex: (key? prev vertex)? -> prev\[vertex] -> null
    ]
    reverse 'result
    return result
]

graph: initGraph [
    ["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]
]

print ["Shortest path from 'a' to 'e': " join.with:" -> " dijkstraPath graph "a" "e"] 
print ["Shortest path from 'a' to 'f': " join.with:" -> " dijkstraPath graph "a" "f"]
Output:
Shortest path from 'a' to 'e':  a -> c -> d -> e 
Shortest path from 'a' to 'f':  a -> c -> f

ATS

This implementation is based on suggestions from a Wikipedia article about Dijkstra's algorithm, although I use a different method to determine whether a queue entry is obsolete.

I prove that the algorithm terminates and that the priority queue has at least enough storage. The priority queue is a binary heap implemented as an array.

(*------------------------------------------------------------------*)

(* Dijkstra's algorithm. *)

(* I demonstrate Dijkstra's algorithm using a rudimentary priority
   queue. For a practical implementation, you would use a fast
   implementation of priority queue. *)

%{^
#include <math.h>
%}

#include "share/atspre_staload.hats"
staload UN = "prelude/SATS/unsafe.sats"

#define NIL list_nil ()
#define ::  list_cons

typedef flt = double
macdef zero = 0.0
macdef infinity = $extval (flt, "INFINITY")

prfn
mul_compare_lte
          {i, j, n : nat | i <= j}
          ()
    :<prf> [i * n <= j * n] void =
  mul_gte_gte_gte {j - i, n} ()

prfn
mul_compare_lt
          {i, j, n : int | 0 <= i; i < j; 1 <= n}
          ()
    :<prf> [i * n < j * n] void =
  mul_compare_lte {i + 1, j, n} ()

(*------------------------------------------------------------------*)
(* Constructing a graph. *)

fn
extract_vertices
          (edges : List @(string, string, double))
    :<!wrt> [n : nat]
            @(arrayref (string, n),
              size_t n) =
  let
    fun
    list_the_vertices
              {m  : nat}
              {n0 : nat}
              .<m>.
              (edges : list (@(string, string, double), m),
               accum : list (string, n0),
               n0    : size_t n0)
        :<!wrt> [n1 : nat]
                @(list (string, n1), size_t n1) =
      case+ edges of
      | NIL => @(accum, n0)
      | @(v1, v2, _) :: tail =>
        let
          implement list_find$pred<string> x = (x = v1)
        in
          case+ list_find_opt accum of
          | ~ None_vt () =>
            let
              implement list_find$pred<string> x = (x = v2)
            in
              case+ list_find_opt accum of
              | ~ None_vt () =>
                list_the_vertices (tail, v2 :: v1 :: accum,
                                   succ (succ n0))
              | ~ Some_vt _ =>
                list_the_vertices (tail, v1 :: accum, succ n0)
            end
          | ~ Some_vt _ =>
            let
              implement list_find$pred<string> x = (x = v2)
            in
              case+ list_find_opt accum of
              | ~ None_vt () =>
                list_the_vertices (tail, v2 :: accum, succ n0)
              | ~ Some_vt _ => list_the_vertices (tail, accum, n0)
            end
        end

    prval () = lemma_list_param edges
    val @(vertex_lst, n) = list_the_vertices (edges, NIL, i2sz 0)
    val vertex_arr = arrayref_make_list<string> (sz2i n, vertex_lst)
  in
    @(vertex_arr, n)
  end

fn
vertex_name_to_index
          {n          : int}
          (vertex_arr : arrayref (string, n),
           n          : size_t n,
           name       : string)
    :<!ref> Option ([i : nat | i < n] size_t i) =
  let
    fun
    loop {i : nat | i <= n}
         .<n - i>.
         (i : size_t i)
        :<!ref> Option ([i : nat | i < n] size_t i) =
      if i = n then
        None ()
      else if name = vertex_arr[i] then
        Some i
      else
        loop (succ i)

    prval () = lemma_arrayref_param vertex_arr
  in
    loop (i2sz 0)
  end

fn
make_adjacency_matrix
          (edges : List @(string, string, double))
    :<!refwrt> [n : nat]
               @(matrixref (flt, n, n),
                 arrayref (string, n),
                 size_t n) =
  let
    val @(vertex_arr, n) = extract_vertices edges
    val adj_matrix = matrixref_make_elt<flt> (n, n, infinity)

    fun
    loop {m     : nat}
         .<m>.
         (edges : list (@(string, string, double), m))
        :<!refwrt> void =
      case+ edges of
      | NIL => ()
      | @(v1, v2, cost) :: tail =>
        let
          val- Some i = vertex_name_to_index (vertex_arr, n, v1)
          and  Some j = vertex_name_to_index (vertex_arr, n, v2)
        in
          adj_matrix[i, n, j] := cost;
          loop tail
        end

    prval () = lemma_list_param edges
  in
    loop edges;
    @(adj_matrix, vertex_arr, n)
  end

fn
fprint_vertex_path
          {n              : int}
          (outf           : FILEref,
           vertex_arr     : arrayref (string, n),
           path           : List ([i : nat | i < n] size_t i),
           cost_opt       : Option flt,
           cost_column_no : size_t)
    : void =
  let
    fun
    loop {m : nat}
         .<m>.
         (path      : list ([i : nat | i < n] size_t i, m),
          column_no : size_t)
        : size_t =
      case+ path of
      | NIL => column_no
      | i :: NIL =>
        begin
          fprint! (outf, vertex_arr[i]);
          column_no + strlen vertex_arr[i]
        end
      | i :: tail =>
        begin
          fprint! (outf, vertex_arr[i], " -> ");
          loop (tail, column_no + strlen vertex_arr[i] + i2sz 4)
        end

    prval () = lemma_list_param path
    val column_no = loop (path, i2sz 1)
  in
    case+ cost_opt of
    | None () => ()
    | Some cost =>
      let
        var i : size_t = column_no
      in
        while (i < cost_column_no)
          begin
            fprint! (outf, " ");
            i := succ i
          end;
        fprint! (outf, "(cost = ", cost, ")")
      end
  end

(*------------------------------------------------------------------*)
(* A binary-heap priority queue, similar to the Pascal in Robert
   Sedgewick, "Algorithms", 2nd ed. (reprinted with corrections),
   1989. Note that Sedgewick does an extract-max, whereas we do an
   extract-min.
   
   Niklaus Wirth, within the heapsort implementation of "Algorithms +
   Data Structures = Programs", has, I will note, some Pascal code
   that is practically the same as Sedgewick's. Can we trace that code
   back farther to Algol?
   
   We do not have "goto" for Sedgewick's "downheap" (or Wirth's
   "sift"), but do have mutual tail call as an obvious alternative to
   the "goto". Nevertheless, because the code "jumped to" is small, I
   simply use a macro to duplicate it. *)

dataprop PQUEUE_N_MAX (n_max : int) =
| {0 <= n_max}
  PQUEUE_N_MAX (n_max)

typedef pqueue (priority_t : t@ype+,
                value_t    : t@ype+,
                n          : int,
                n_max      : int) =
  [n <= n_max]
  @{
    (* An earlier version of this structure stored a copy of n_max,
       but the following use of the PQUEUE_N_MAX prop eliminates the
       need for that. Instead the information is kept only at
       typechecking time. *)
    pf    = PQUEUE_N_MAX (n_max) |
    arr   = arrayref (@(priority_t, value_t), n_max + 1),
    n     = size_t n
  }

prfn
lemma_pqueue_param
          {n_max : int}
          {n     : int}
          {priority_t, value_t : t@ype}
          (pq : pqueue (priority_t, value_t, n, n_max))
    :<prf> [0 <= n; n <= n_max] void =
  lemma_g1uint_param (pq.n)

extern praxi
lemma_pqueue_size
          {n_max : int}
          {n     : int}
          {priority_t, value_t : t@ype}
          (pq : pqueue (priority_t, value_t, n, n_max))
    :<prf> [n1 : int | n1 == n] void

extern fn {priority_t : t@ype}
pqueue$cmp :
  (priority_t, priority_t) -<> int

extern fn {priority_t : t@ype}
pqueue$priority_min :
  () -<> priority_t

implement pqueue$cmp<double> (x, y) = compare (x, y)
implement pqueue$priority_min<double> () = neg infinity

fn {priority_t : t@ype}
   {value_t    : t@ype}
pqueue_make_empty
          {n_max           : int}
          (n_max           : size_t n_max,
           arbitrary_entry : @(priority_t, value_t))
    :<!wrt> pqueue (priority_t, value_t, 0, n_max) =
  let
    (* Currently an array is allocated whose size is the proven
       bound. It might be better to use a smaller array and allow
       reallocation up to this maximum size, or to break the array
       into pieces. *)

    prval () = lemma_g1uint_param n_max
    val arr =
      arrayref_make_elt<@(priority_t, value_t)>
        (succ n_max, arbitrary_entry)
  in
    @{pf = PQUEUE_N_MAX {n_max} () |
      arr = arr,
      n = i2sz 0}
  end

fn {}
pqueue_clear
          {n_max      : int}
          {n          : int}
          {priority_t : t@ype}
          {value_t    : t@ype}
          (pq         : &pqueue (priority_t, value_t, n, n_max)
                        >> pqueue (priority_t, value_t, 0, n_max))
    :<!wrt> void =
  let
    prval PQUEUE_N_MAX () = pq.pf (* Proves 0 <= n_max. *)
  in
    pq := @{pf = pq.pf |
            arr = pq.arr,
            n = i2sz 0}
  end

fn {}
pqueue_is_empty
          {n_max      : int}
          {n          : int}
          {priority_t : t@ype}
          {value_t    : t@ype}
          (pq         : pqueue (priority_t, value_t, n, n_max))
    :<> bool (n == 0) =
  (pq.n) = i2sz 0

fn {}
pqueue_size
          {n_max      : int}
          {n          : int}
          {priority_t : t@ype}
          {value_t    : t@ype}
          (pq         : pqueue (priority_t, value_t, n, n_max))
    :<> size_t n =
  pq.n

fn {priority_t : t@ype}
   {value_t    : t@ype}
_upheap {n_max : pos}
        {n     : int | n <= n_max}
        {k0    : nat | k0 <= n}
        (arr   : arrayref (@(priority_t, value_t), n_max + 1),
         k0    : size_t k0)
    :<!refwrt> void =
  let
    macdef lt (x, y) = (pqueue$cmp<priority_t> (,(x), ,(y)) < 0)
    macdef prio x = ,(x).0

    val entry = arr[k0]

    fun
    loop {k : nat | k <= n}
         .<k>.
         (k : size_t k)
        :<!refwrt> void =
      if k = i2sz 0 then
        arr[k] := entry
      else
        let
          val kh = half k
        in
          if (prio entry) \lt (prio arr[kh]) then
            begin
              arr[k] := arr[kh];
              loop kh
            end
          else
            arr[k] := entry
        end
  in
    arr[0] := @(pqueue$priority_min<priority_t> (), arr[0].1);
    loop k0
  end

fn {priority_t : t@ype}
   {value_t    : t@ype}
pqueue_insert
          {n_max : int}
          {n     : int | n < n_max}
          (pq    : &pqueue (priority_t, value_t, n, n_max)
                    >> pqueue (priority_t, value_t, n + 1, n_max),
           entry : @(priority_t, value_t))
    :<!refwrt> void =
  let
    prval () = lemma_g1uint_param (pq.n)
    val arr = pq.arr
    and n1 = succ (pq.n)
  in
    arr[n1] := entry;
    _upheap {n_max} {n + 1} (arr, n1);
    pq := @{pf = pq.pf |
            arr = arr,
            n = n1}
  end

fn {priority_t : t@ype}
   {value_t    : t@ype}
_downheap {n_max : pos}
          {n     : pos | n <= n_max}
          (arr   : arrayref (@(priority_t, value_t), n_max + 1),
           n     : size_t n)
    :<!refwrt> void =
  let
    macdef lt (x, y) = (pqueue$cmp<priority_t> (,(x), ,(y)) < 0)
    macdef prio x = ,(x).0

    val entry = arr[1]
    and nh = half n

    fun
    loop {k : pos | k <= n}
         .<n - k>.
         (k : size_t k)
        :<!refwrt> void =
      let
        macdef move_data i =
          if (prio entry) \lt (prio arr[,(i)]) then
            arr[k] := entry
          else
            begin
              arr[k] := arr[,(i)];
              loop ,(i)
            end
      in
        if nh < k then
          arr[k] := entry
        else
          let
            stadef j = 2 * k
            prval () = prop_verify {j <= n} ()
            val j : size_t j = k + k
          in
            if j < n then
              let
                stadef j1 = j + 1
                prval () = prop_verify {j1 <= n} ()
                val j1 : size_t j1 = succ j
              in
                if ~((prio arr[j]) \lt (prio arr[j1])) then
                  move_data j1
                else
                  move_data j
              end
            else
              move_data j
          end
      end
  in
    loop (i2sz 1)
  end

fn {priority_t : t@ype}
   {value_t    : t@ype}
pqueue_peek
          {n_max : int}
          {n     : pos | n <= n_max}
          (pq    : pqueue (priority_t, value_t, n, n_max))
    :<!ref> @(priority_t, value_t) =
  let
    val arr = pq.arr
  in
    arr[1]
  end

fn {priority_t : t@ype}
   {value_t    : t@ype}
pqueue_delete
          {n_max : int}
          {n     : pos | n <= n_max}
          (pq    : &pqueue (priority_t, value_t, n, n_max)
                    >> pqueue (priority_t, value_t, n - 1, n_max))
    :<!refwrt> void =
  let
    val @{pf = pf |
          arr = arr,
          n = n} = pq
  in
    if i2sz 0 < pred n then
      begin
        arr[1] := arr[n];
        _downheap {n_max} {n - 1} (arr, pred n)
      end;
    pq := @{pf = pf |
            arr = arr,
            n = pred n}
  end

fn {priority_t : t@ype}
   {value_t    : t@ype}
pqueue_extract
          {n_max : int}
          {n     : pos | n <= n_max}
          (pq    : &pqueue (priority_t, value_t, n, n_max)
                    >> pqueue (priority_t, value_t, n - 1, n_max))
    :<!refwrt> @(priority_t, value_t) =
  let
    val retval = pqueue_peek<priority_t><value_t> {n_max} {n} pq
  in
    pqueue_delete<priority_t><value_t> {n_max} {n} pq;
    retval
  end

local                   (* A little unit testing of the priority queue
                           implementation. *)
  #define NMAX 10
in
  var pq = pqueue_make_empty<double><int> (i2sz NMAX, @(0.0, 0))
  val- true = pqueue_is_empty pq
  val- true = (pqueue_size pq = i2sz 0)
  val () = pqueue_insert (pq, @(3.0, 3))
  val () = pqueue_insert (pq, @(5.0, 5))
  val () = pqueue_insert (pq, @(1.0, 1))
  val () = pqueue_insert (pq, @(2.0, 2))
  val () = pqueue_insert (pq, @(4.0, 4))
  val- false = pqueue_is_empty pq
  val- true = (pqueue_size pq = i2sz 5)
  val- @(1.0, 1) = pqueue_extract<double> pq
  val- @(2.0, 2) = pqueue_extract<double> pq
  val- @(3.0, 3) = pqueue_extract<double> pq
  val- @(4.0, 4) = pqueue_extract<double> pq
  val- @(5.0, 5) = pqueue_extract<double> pq
  val- true = pqueue_is_empty pq
  val- true = (pqueue_size pq = i2sz 0)
end

(*------------------------------------------------------------------*)
(* Dijkstra's algorithm. *)

fn
dijkstra_algorithm
          {n          : int}
          {source     : nat | source < n}
          (adj_matrix : matrixref (flt, n, n),
           n          : size_t n,
           source     : size_t source)
    (* Returns total-costs and previous-hops arrays. *)
    :<!refwrt> @(arrayref (flt, n),
                 arrayref ([i : nat | i <= n] size_t i, n)) =
  let
    prval () = lemma_matrixref_param adj_matrix

    typedef index_t = [i : nat | i <= n] size_t i
    typedef defined_index_t = [i : nat | i < n] size_t i
    val index_t_undefined : size_t n = n

    val arbitrary_pq_entry : @(flt, defined_index_t) =
      @(0.0, i2sz 0)

    val prev = arrayref_make_elt<index_t> (n, index_t_undefined)
    and cost = arrayref_make_elt<flt> (n, infinity)
    val () = cost[source] := zero

    (* The priority queue never gets larger than m_max. There is code
       below that proves this; thus there is no risk of overrunning
       the queue's storage (unless the queue implementation itself is
       made unsafe). FIXME: Is it possible to prove a tighter bound on
       the size of the priority queue? *)
    stadef m_max = (n * n) + n + n
    prval () = mul_pos_pos_pos (mul_make {n, n} ())
    prval () = prop_verify {n + n < m_max} ()
    val m_max : size_t m_max = (n * n) + n + n

    typedef pqueue_t (m : int) =
      [0 <= m; m <= m_max]
      pqueue (flt, defined_index_t, m, m_max)
    typedef pqueue_t =
      [m : int] pqueue_t m

    fn
    pq_make_empty ()
        :<!wrt> pqueue_t 0 =
      (* Create a priority queue, whose maximum size is our proven
         upper bound on the queue size. *)
      pqueue_make_empty<flt><defined_index_t>
        (m_max, arbitrary_pq_entry)

    var pq = pq_make_empty ()
    val active = arrayref_make_elt<bool> (n, true)
    var num_active : [i : nat | i <= n] size_t i = n

    fun
    fill_pq {i : nat | i <= n}
            .<n - i>.
            (pq : &pqueue_t i >> pqueue_t n,
             i  : size_t i)
        :<!refwrt> void =
      if i <> n then
        begin
          pqueue_insert {m_max} {i} (pq, @(cost[i], i));
          fill_pq {i + 1} (pq, succ i)
        end

    fun
    extract_min
              {m0 : pos | m0 + n <= m_max}
              .<m0>.
              (pq : &pqueue_t m0 >> pqueue_t m1)
        :<!refwrt> #[m1 : nat | m1 < m0]
                   @(flt, defined_index_t) =
      let
        val @(priority, vertex) =
          pqueue_extract<flt><defined_index_t> {m_max} {m0} pq
      in
        if active[vertex] then
          @(priority, vertex)
        else if pqueue_is_empty {m_max} pq then
          arbitrary_pq_entry
        else
          extract_min pq
      end

    fun
    main_loop {num_active0 : nat | num_active0 <= n}
              {qsize0      : nat}
              {qlimit0     : int | 0 <= qlimit0;
                                   qsize0 <= qlimit0 + n}
              .<num_active0>.
              (* The pf_qlimit0 prop helps us prove a bound on the
                 size of the priority queue. We need it because the
                 proof capabilities built into ATS have very limited
                 ability to handle multiplication. *)
              (pf_qlimit0 : MUL (n - num_active0, n, qlimit0) |
               pq         : &pqueue_t qsize0 >> pqueue_t 0,
               num_active : &size_t num_active0 >> size_t num_active1)
        :<!refwrt> #[num_active1 : nat | num_active1 <= num_active0]
                   void =
      if num_active = i2sz 0 then
        pqueue_clear pq
      else if pqueue_is_empty {m_max} {qsize0} pq then
        let                     (* This should not happen. *)
          val- false = true
        in
        end
      else
        let
          prval () = mul_elim pf_qlimit0
          prval () =
            prop_verify {qsize0 <= ((n - num_active0) * n) + n} ()
          prval () = mul_compare_lt {n - num_active0, n, n} ()
          prval () = prop_verify {qsize0 < m_max} ()

          val @(priority, u) = extract_min pq
          prval [qsize : int] () = lemma_pqueue_size {m_max} pq
          prval () = lemma_pqueue_param {m_max} {qsize} pq
          prval () = prop_verify {qsize < qsize0} ()
          prval () = prop_verify {qsize < m_max} ()

          val () = active[u] := false
          and () = num_active := pred num_active

          fun
          loop_over_vertices
                    {v  : nat | v <= n}
                    {m0 : nat | qsize <= m0; m0 <= qsize + v}
                    .<n - v>.
                    (pq : &pqueue_t m0 >> pqueue_t m1,
                     v  : size_t v)
              :<!refwrt> #[m1 : int | qsize <= m1; m1 <= qsize + n]
                         void =
            if v = n then
              ()
            else if ~active[v] then
              loop_over_vertices {v + 1} {m0} (pq, succ v)
            else
              let
                val alternative = cost[u] + adj_matrix[u, n, v]
              in
                if alternative < cost[v] then
                  let
                    prval () = prop_verify {m0 < m_max} ()
                  in
                    cost[v] := alternative;
                    prev[v] := u;

                    (* Rather than lower the priority of v, this
                       implementation inserts a new entry for v and
                       ignores obsolete queue entries. Queue entries
                       are obsolete if the vertex's entry in the
                       "active" array is false. *)

                    pqueue_insert<flt><defined_index_t>
                      {m_max} {m0}
                      (pq, @(alternative, v));

                    loop_over_vertices {v + 1} {m0 + 1}
                                       (pq, succ v)
                  end
                else
                  loop_over_vertices {v + 1} {m0} (pq, succ v)
              end

          val () = loop_over_vertices {0} {qsize} (pq, i2sz 0)
        in
          main_loop {num_active0 - 1}
                    (MULind pf_qlimit0 | pq, num_active)
        end
  in
    fill_pq {0} (pq, i2sz 0);
    main_loop {n} {n} (MULbas () | pq, num_active);
    @(cost, prev)
  end

fn
least_cost_path
        {n           : int}
        (source      : [i : nat | i < n] size_t i,
         prev        : arrayref ([i : nat | i <= n] size_t i, n),
         n           : size_t n,
         destination : [i : nat | i < n] size_t i)
    :<!refwrt> Option (List1 ([i : nat | i < n] size_t i)) =
  let
    prval () = lemma_arrayref_param prev

    typedef index_t = [i : nat | i <= n] size_t i
    typedef defined_index_t = [i : nat | i < n] size_t i
    val index_t_undefined : size_t n = n

    fun
    loop {i : nat | i <= n}
         .<n - i>.
         (u            : defined_index_t,
          accum        : List1 defined_index_t,
          loop_counter : size_t i)
        :<!refwrt> Option (List1 defined_index_t) =
      if loop_counter = n then
        None ()
      else if u = source then
        Some accum
      else
        let
          val previous = prev[u]
        in
          if previous = index_t_undefined then
            None ()
          else
            loop (previous, previous :: accum, succ loop_counter)
        end
  in
    loop (destination, destination :: NIL, i2sz 0)
  end

(*------------------------------------------------------------------*)

val example_edges =
  $list (@("a", "b", 7.0),
         @("a", "c", 9.0),
         @("a", "f", 14.0),
         @("b", "c", 10.0),
         @("b", "d", 15.0),
         @("c", "d", 11.0),
         @("c", "f", 2.0),
         @("d", "e", 6.0),
         @("e", "f", 9.0))

implement
main0 () =
  let
    val @(adj_matrix, vertex_arr, n) =
      make_adjacency_matrix example_edges

    prval [n : int] EQINT () = eqint_make_guint n

    val- Some a = vertex_name_to_index (vertex_arr, n, "a")
    val- Some e = vertex_name_to_index (vertex_arr, n, "e")
    val- Some f = vertex_name_to_index (vertex_arr, n, "f")

    val @(cost, prev) = dijkstra_algorithm (adj_matrix, n, a)

    val- Some path_a_to_e = least_cost_path {n} (a, prev, n, e)
    val- Some path_a_to_f = least_cost_path {n} (a, prev, n, f)

    var u : [i : nat | i <= n] size_t i
    val cost_column_no = i2sz 20
  in
    println! ("The requested paths:");
    fprint_vertex_path (stdout_ref, vertex_arr, path_a_to_e,
                        Some cost[e], cost_column_no);
    println! ();
    fprint_vertex_path (stdout_ref, vertex_arr, path_a_to_f,
                        Some cost[f], cost_column_no);
    println! ();
    println! ();
    println! ("All paths (in no particular order):");
    for (u := i2sz 0; u <> n; u := succ u)
      case+ least_cost_path {n} (a, prev, n, u) of
      | None () =>
        println! ("There is no path from ", vertex_arr[a], " to ",
                  vertex_arr[u], ".")
      | Some path =>
        begin
          fprint_vertex_path (stdout_ref, vertex_arr, path,
                              Some cost[u], cost_column_no);
          println! ()
        end
  end

(*------------------------------------------------------------------*)
Output:
$ patscc -O3 -DATS_MEMALLOC_GCBDW dijkstra-algorithm.dats -lgc && ./a.out
The requested paths:
a -> c -> d -> e   (cost = 26.000000)
a -> c -> f        (cost = 11.000000)

All paths (in no particular order):
a -> c -> d -> e   (cost = 26.000000)
a -> c -> d        (cost = 20.000000)
a -> c -> f        (cost = 11.000000)
a -> c             (cost = 9.000000)
a -> b             (cost = 7.000000)
a                  (cost = 0.000000)

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,, From:
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

AWK

A very basic implementation in AWK. Minimum element in the queue is found by a linear search.

NF == 3 { graph[$1,$2] = $3 }
NF == 2 {
    weight = shortest($1, $2)
    n = length(path)
    p = $1
    for (i = 2; i < n; i++)
        p = p "-" path[i]
    print p "-" $2 " (" weight ")"
}

# Edge weights are in graph[node1,node2]
# Returns the weight of the shortest path
# Shortest path is in path[1] ... path[n]
function shortest(from, to,    queue, q, dist, v, i, min, edge, e, prev, n) {
    delete path
    dist[from] = 0
    queue[q=1] = from

    while (q > 0) {
        min = 1
        for (i = 2; i <= q; i++)
            if (dist[queue[i]] < dist[queue[min]])
                min = i
        v = queue[min]
        queue[min] = queue[q--]

        if (v == to)
            break
        for (edge in graph) {
            split(edge, e, SUBSEP)
            if (e[1] != v)
                continue
            if (!(e[2] in dist) || dist[e[1]] + graph[edge] < dist[e[2]]) {
                dist[e[2]] = dist[e[1]] + graph[edge]
                prev[e[2]] = e[1]
                queue[++q] = e[2]
            }
        }
    }
    if (v != to)
        return "n/a"

    # Build the path
    n = 1
    for (v = to; v != from; v = prev[v])
        n++
    for (v = to; n > 0; v = prev[v])
       path[n--] = v 
    return dist[to]
}

Example:

$ cat dijkstra.txt
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
a e
a f
f a

$ awk -f dijkstra.awk dijkstra.txt
a-c-d-e (26)
a-c-f (11)
f-a (n/a)

BASIC

Applesoft BASIC

100 O$ = "A" : T$ = "EF"
110 DEF FN N(P) = ASC(MID$(N$,P+(P=0),1))-64
120 DIM D(26),UNVISITED(26)
130 DIM PREVIOUS(26) : TRUE = 1
140 LET M = -1 : INFINITY = M
150 FOR I = 0 TO 26
160     LET D(I) = INFINITY : NEXT
170 FOR NE = M TO 1E38 STEP .5
180     READ C$
190     IF LEN(C$) THEN NEXT
200 DIM C(NE),FROM(NE),T(NE)
210 DIM PC(NE) : RESTORE
220 FOR I = 0 TO NE
230     READ C(I), N$
240     LET FROM(I) = FN N(1)
250     LET UNVISITED(FR(I)) = TRUE
260     LET T(I) = FN N(3)
270     LET UNVISITED(T(I)) = TRUE
290 NEXT
300 N$ = O$ : O = FN N(0)
310 D(O) = 0
320 FOR CV = O TO EMPTY STEP 0
330     FOR I = 0 TO NE
340         IF FROM(I) = CV THEN N = T(I) : D = D(CV) + C(I) : IF (D(N) = INFINITY) OR (D < D(N)) THEN D(N) = D : PREVIOUS(N) = CV : PC(N) = C(I)
350     NEXT I
360     LET UNVISITED(CV) = FALSE
370     LET MV =  EMPTY
380     FOR I = 1 TO 26
390         IF UNVISITED(I) THEN MD = D(MV) * (MV <> INFINITY) + INFINITY * (MV = INFINITY) : IF (D(I) <> INFINITY) AND ((MD = INFINITY) OR (D(I) < MD)) THEN MV = I
400     NEXT I
410     LET CV = MV * (MD <> INF)    
420 NEXT CV : M$ = CHR$(13)
430 PRINT "SHORTEST PATH";
440 FOR I = 1 TO LEN(T$)
450     LET N$ = MID$(T$, I, 1)
460     PRINT M$ "    FROM " O$;
470     PRINT " TO "; : N = FN N(0)
480     IF D(N) = INFINITY THEN PRINT N$" DOES NOT EXIST.";
490     IF D(N) <> INFINITY THEN FOR N = N TO FALSE STEP 0 : PRINT CHR$(N + 64); : IF N <  > O THEN  PRINT " <- "; : N = PREVIOUS(N): NEXT N
500     IF D(N) <> INFINITY THEN PRINT : PRINT "      IS "; : N = FN N(0) : PRINT D(N); : H = 15 : FOR N = N TO O STEP 0: IF N <  > O THEN  P = PREVIOUS(N): PRINT TAB(H)CHR$(43+18*(h=15));TAB(H+2)PC(N); :N = P: H=H+5: NEXT N
510 NEXT I
600 DATA  7,A-B
610 DATA  9,A-C
620 DATA 14,A-F
630 DATA 10,B-C
640 DATA 15,B-D
650 DATA 11,C-D
660 DATA  2,C-F
670 DATA  6,D-E
680 DATA  9,E-F
690 DATA
Output:
SHORTEST PATH
    FROM A TO E <- D <- C <- A
      IS 26   = 6  + 11 + 9
    FROM A TO F <- C <- A
      IS 11   = 2  + 9

Commodore BASIC

This should work on any Commodore 8-bit BASIC from V2 on; with the given sample data, it even runs on an unexpanded VIC-20.

(The program outputs the shortest path to each node in the graph, including E and F, so I assume that meets the requirements of Task item 3.)

100 NV=0: REM NUMBER OF VERTICES
110 READ N$:IF N$<>"" THEN NV=NV+1:GOTO 110
120 NE=0: REM NUMBER OF EDGES
130 READ N1:IF N1 >= 0 THEN READ N2,W:NE=NE+1:GOTO 130
140 DIM VN$(NV-1),VD(NV-1,2): REM VERTEX NAMES AND DATA
150 DIM ED(NE-1,2): REM EDGE DATA
160 RESTORE
170 FOR I=0 TO NV-1
180 : READ VN$(I):  REM VERTEX NAME
190 : VD(I,0) = -1: REM DISTANCE = INFINITY
200 : VD(I,1) = 0:  REM NOT YET VISITED
210 : VD(I,2) = -1: REM NO PREV VERTEX YET
220 NEXT I
230 READ N$: REM SKIP SENTINEL
240 FOR I=0 TO NE-1
250 : READ ED(I,0),ED(I,1),ED(I,2): REM EDGE FROM, TO, WEIGHT
260 NEXT I
270 READ N1: REM SKIP SENTINEL
280 READ O: REM ORIGIN VERTEX
290 :
300 REM BEGIN DIJKSTRA'S
310 VD(O,0) = 0: REM DISTANCE TO ORIGIN IS 0
320 CV = 0: REM CURRENT VERTEX IS ORIGIN
330 FOR I=0 TO NE-1
340 : IF ED(I,0)<>CV THEN 390: REM SKIP EDGES NOT FROM CURRENT
350 : N=ED(I,1): REM NEIGHBOR VERTEX
360 : D=VD(CV,0) + ED(I,2): REM TOTAL DISTANCE TO NEIGHBOR THROUGH THIS PATH
370 : REM IF PATH THRU CV < DISTANCE, UPDATE DISTANCE AND PREV VERTEX
380 : IF (VD(N,0)=-1) OR (D<VD(N,0)) THEN VD(N,0) = D:VD(N,2)=CV
390 NEXT I
400 VD(CV,1)=1: REM CURRENT VERTEX HAS BEEN VISITED
410 MV=-1: REM VERTEX WITH MINIMUM DISTANCE SEEN
420 FOR I=0 TO NV-1
430 : IF VD(I,1) THEN 470: REM SKIP VISITED VERTICES
440 : REM IF THIS IS THE SMALLEST DISTANCE SEEN, REMEMBER IT
450 : MD=-1:IF MV > -1 THEN MD=VD(MV,0)
460 : IF ( VD(I,0)<>-1 ) AND ( ( MD=-1 ) OR ( VD(I,0)<MD ) ) THEN MV=I
470 NEXT I
480 IF MD=-1 THEN 510: REM END IF ALL VERTICES VISITED OR AT INFINITY
490 CV=MV
500 GOTO 330
510 PRINT "SHORTEST PATH TO EACH VERTEX FROM "VN$(O)":";CHR$(13)
520 FOR I=0 TO NV-1
530 : IF I=0 THEN 600
540 : PRINT VN$(I)":"VD(I,0)"(";
550 : IF VD(I,0)=-1 THEN 600
560 : N=I
570 : PRINT VN$(N);
580 : IF N<>O THEN PRINT "←";:N=VD(N,2):GOTO 570
590 : PRINT ")"
600 NEXT I
610 DATA A,B,C,D,E,F,""
620 DATA 0,1,7
630 DATA 0,2,9
640 DATA 0,5,14
650 DATA 1,2,10
660 DATA 1,3,15
670 DATA 2,3,11
680 DATA 2,5,2
690 DATA 3,4,6
700 DATA 4,5,9
710 DATA -1
720 DATA 0
Output:

Paths are printed right-to-left mainly because PETSCII includes a left-facing arrow and not a right-facing one:

SHORTEST PATH TO EACH VERTEX FROM A:

B: 7 (B←A)
C: 9 (C←A)
D: 20 (D←C←A)
E: 26 (E←D←C←A)
F: 11 (F←C←A)

VBA

Class Branch
Public from As Node '[according to Dijkstra the first Node should be closest to P]
Public towards As Node
Public length As Integer '[directed length!]
Public distance As Integer '[from P to farthest node]
Public key As String
Class Node
Public key As String
Public correspondingBranch As Branch
Const INFINITY = 32767
Private Sub Dijkstra(Nodes As Collection, Branches As Collection, P As Node, Optional Q As Node)
    'Dijkstra, E. W. (1959). "A note on two problems in connexion with graphs".
    'Numerische Mathematik. 1: 269–271. doi:10.1007/BF01386390.
    'http://www-m3.ma.tum.de/twiki/pub/MN0506/WebHome/dijkstra.pdf
    'Problem 2. Find the path of minimum total length between two given nodes
    'P and Q.
    'We use the fact that, if R is a node on the minimal path from P to Q, knowledge
    'of the latter implies the knowledge of the minimal path from P to A. In the
    'solution presented, the minimal paths from P to the other nodes are constructed
    'in order of increasing length until Q is reached.
    'In the course of the solution the nodes are subdivided into three sets:
    'A. the nodes for which the path of minimum length from P is known; nodes
    'will be added to this set in order of increasing minimum path length from node P;
    '[comments in square brackets are not by Dijkstra]
    Dim a As New Collection '[of nodes (vertices)]
    'B. the nodes from which the next node to be added to set A will be selected;
    'this set comprises all those nodes that are connected to at least one node of
    'set A but do not yet belong to A themselves;
    Dim b As New Collection '[of nodes (vertices)]
    'C. the remaining nodes.
    Dim c As New Collection '[of nodes (vertices)]
    'The Branches are also subdivided into three sets:
    'I the Branches occurring in the minimal paths from node P to the nodes
    'in set A;
    Dim I As New Collection '[of Branches (edges)]
    'II the Branches from which the next branch to be placed in set I will be
    'selected; one and only one branch of this set will lead to each node in set B;
    Dim II As New Collection '[of Branches (edges)]
    'III. the remaining Branches (rejected or not yet considered).
    Dim III As New Collection '[of Branches (edges)]
    Dim u As Node, R_ As Node, dist As Integer
    'To start with, all nodes are in set C and all Branches are in set III. We now
    'transfer node P to set A and from then onwards repeatedly perform the following
    'steps.
    For Each n In Nodes
        c.Add n, n.key
    Next n
    For Each e In Branches
        III.Add e, e.key
    Next e
    a.Add P, P.key
    c.Remove P.key
    Set u = P
    Do
        'Step 1. Consider all Branches r connecting the node just transferred to set A
        'with nodes R in sets B or C. If node R belongs to set B, we investigate whether
        'the use of branch r gives rise to a shorter path from P to R than the known
        'path that uses the corresponding branch in set II. If this is not so, branch r is
        'rejected; if, however, use of branch r results in a shorter connexion between P
        'and R than hitherto obtained, it replaces the corresponding branch in set II
        'and the latter is rejected. If the node R belongs to set C, it is added to set B and
        'branch r is added to set II.
        For Each r In III
            If r.from Is u Then
                Set R_ = r.towards
                If Belongs(R_, c) Then
                    c.Remove R_.key
                    b.Add R_, R_.key
                    Set R_.correspondingBranch = r
                    If u.correspondingBranch Is Nothing Then
                        R_.correspondingBranch.distance = r.length
                    Else
                        R_.correspondingBranch.distance = u.correspondingBranch.distance + r.length
                    End If
                    III.Remove r.key '[not mentioned by Dijkstra ...]
                    II.Add r, r.key
                Else
                    If Belongs(R_, b) Then '[initially B is empty ...]
                        If R_.correspondingBranch.distance > u.correspondingBranch.distance + r.length Then
                            II.Remove R_.correspondingBranch.key
                            II.Add r, r.key
                            Set R_.correspondingBranch = r '[needed in step 2.]
                            R_.correspondingBranch.distance = u.correspondingBranch.distance + r.length 
                        End If
                    End If
                End If
            End If
        Next r
        'Step 2. Every node in set B can be connected to node P in only one way
        'if we restrict ourselves to Branches from set I and one from set II. In this sense
        'each node in set B has a distance from node P: the node with minimum distance
        'from P is transferred from set B to set A, and the corresponding branch is transferred
        'from set II to set I. We then return to step I and repeat the process
        'until node Q is transferred to set A. Then the solution has been found.
        dist = INFINITY
        Set u = Nothing
        For Each n In b
            If dist > n.correspondingBranch.distance Then
                dist = n.correspondingBranch.distance
                Set u = n
            End If
        Next n
        b.Remove u.key
        a.Add u, u.key
        II.Remove u.correspondingBranch.key
        I.Add u.correspondingBranch, u.correspondingBranch.key
    Loop Until IIf(Q Is Nothing, a.Count = Nodes.Count, u Is Q)
    If Not Q Is Nothing Then GetPath Q
End Sub
Private Function Belongs(n As Node, col As Collection) As Boolean
    Dim obj As Node
    On Error GoTo err
        Belongs = True
        Set obj = col(n.key)
        Exit Function
err:
        Belongs = False
End Function
Private Sub GetPath(Target As Node)
    Dim path As String
    If Target.correspondingBranch Is Nothing Then
        path = "no path"
    Else
        path = Target.key
        Set u = Target
        Do While Not u.correspondingBranch Is Nothing
            path = u.correspondingBranch.from.key & " " & path
            Set u = u.correspondingBranch.from
        Loop
        Debug.Print u.key, Target.key, Target.correspondingBranch.distance, path
    End If
End Sub
Public Sub test()
    Dim a As New Node, b As New Node, c As New Node, d As New Node, e As New Node, f As New Node
    Dim ab As New Branch, ac As New Branch, af As New Branch, bc As New Branch, bd As New Branch
    Dim cd As New Branch, cf As New Branch, de As New Branch, ef As New Branch
    Set ab.from = a: Set ab.towards = b: ab.length = 7: ab.key = "ab": ab.distance = INFINITY
    Set ac.from = a: Set ac.towards = c: ac.length = 9: ac.key = "ac": ac.distance = INFINITY
    Set af.from = a: Set af.towards = f: af.length = 14: af.key = "af": af.distance = INFINITY
    Set bc.from = b: Set bc.towards = c: bc.length = 10: bc.key = "bc": bc.distance = INFINITY
    Set bd.from = b: Set bd.towards = d: bd.length = 15: bd.key = "bd": bd.distance = INFINITY
    Set cd.from = c: Set cd.towards = d: cd.length = 11: cd.key = "cd": cd.distance = INFINITY
    Set cf.from = c: Set cf.towards = f: cf.length = 2: cf.key = "cf": cf.distance = INFINITY
    Set de.from = d: Set de.towards = e: de.length = 6: de.key = "de": de.distance = INFINITY
    Set ef.from = e: Set ef.towards = f: ef.length = 9: ef.key = "ef": ef.distance = INFINITY
    a.key = "a"
    b.key = "b"
    c.key = "c"
    d.key = "d"
    e.key = "e"
    f.key = "f"
    Dim testNodes As New Collection
    Dim testBranches As New Collection
    testNodes.Add a, "a"
    testNodes.Add b, "b"
    testNodes.Add c, "c"
    testNodes.Add d, "d"
    testNodes.Add e, "e"
    testNodes.Add f, "f"
    testBranches.Add ab, "ab"
    testBranches.Add ac, "ac"
    testBranches.Add af, "af"
    testBranches.Add bc, "bc"
    testBranches.Add bd, "bd"
    testBranches.Add cd, "cd"
    testBranches.Add cf, "cf"
    testBranches.Add de, "de"
    testBranches.Add ef, "ef"
    Debug.Print "From", "To", "Distance", "Path"
    '[Call Dijkstra with target:]
    Dijkstra testNodes, testBranches, a, e
    '[Call Dijkstra without target computes paths to all reachable nodes:]
    Dijkstra testNodes, testBranches, a
    GetPath f
End Sub
Output:
From          To            Distance      Path

a e 26 a c d e

a f 11 a c f

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';
    add_vertex(g, a);
    add_vertex(g, b);
    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[1];
    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));
    add_edge(g, 'a', 'b', 7);
    add_edge(g, 'a', 'c', 9);
    add_edge(g, 'a', 'f', 14);
    add_edge(g, 'b', 'c', 10);
    add_edge(g, 'b', 'd', 15);
    add_edge(g, 'c', 'd', 11);
    add_edge(g, 'c', 'f', 2);
    add_edge(g, 'd', 'e', 6);
    add_edge(g, 'e', 'f', 9);
    dijkstra(g, 'a', 'e');
    print_path(g, 'e');
    return 0;
}

output 26 acde

C#

Works with: C sharp version 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),
        }) {
            graph.AddEdge(id(start), id(end), cost);
        }

        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
{
    private readonly List<EdgeList> adjacency;

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

    public int Count => adjacency.Count;
    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;
        adjacency[s].Add((e, weight));
        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 visited = new System.Collections.BitArray(adjacency.Count);

        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;
            var edges = adjacency[current.node];
            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 IComparer<T> comparer;
    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) {
        list.Add(element);
        SiftUp(list.Count - 1);
    }

    public T Pop() {
        T result = list[1];
        list[1] = 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;
        }
    }

}
Output:
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)

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.

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

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

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::vector<std::vector<neighbor> > adjacency_list_t;
typedef std::pair<weight_t, vertex_t> weight_vertex_pair_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);
    // 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
	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]) {
	        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
    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;
}

CafeOBJ

Dijkstra's algorithm repeatedly chooses the nearest vertex and relaxes the edges leaving it, terminating when no more vertices are accessible from the origin.

"
This code works with CafeOBJ 1.5.1 and CafeOBJ 1.5.5.
Save this file as  DijkstraRosetta.cafe. 
To run the file type
CafeOBJ> in DijkstraRosetta.cafe
at the CafeOBJ command prompt.

CafeOBJ is primarily a first order specification language which can also be used as a functional programming language.
Being first order, we make no use higher order functions such as map.
There is a minimal library of basic types such as natural numbers, integers, floating point number, and character string. 
There are no libraries for arrays, lists, trees, graphs. 
Hence the user written list module. 


Input
 A directed positively weighted graph. The graph is represented as a list of 4tuples containing directed edges of the form (start, end, edgeDist,pathDist)  
The tuple (start, start,0,0)  means there is zero distance from start to start.

Ouput
1)  a list of 4-tuples with each tuple represents a node N, its source node, length of the connecting edge to N, and the shortest distance from the some starting node to N  .
2)  a list of nodes on the shortest path from a chosen start to some chosen end node. 

Note needs a bit more work to exactly match the specified Rosetta Dijkstra task.
"

-- some system settings
-- Most important is memoization (memo) which stores the value of a function instead of recomputing it each time the function is called.
full reset
set step off
set print mode :fancy
set stats off
set verbose off
set quiet on
set memo on

-- A module defining a simple parameterized list.
mod! LIST(T :: TRIV) principal-sort List {
[Elt < List ]
op nil : -> List          
op (_:_) : List List -> List {memo assoc id: nil}
op reverse_ : List -> List
op head_ : List -> Elt
var e : Elt
var l : List
eq reverse nil = nil .
eq reverse (e : l) = (reverse l) :  e .
eq head e : l = e .
}


-- Main module
mod! DIJKSTRA {
-- We use two different list notations, one for edges the other for paths.
  
-- EdgeList : A four tuple used to store graph and paths and shortest distance
--             start, end, edgeDist,pathDist
  pr(LIST(4TUPLE(CHARACTER,CHARACTER,INT,INT)) *{sort List -> EdgeList, op (_:_) -> (_:e_), op nil -> nilE})
  
-- PathList : A list of characters used to store final shortest path.
  pr(LIST(CHARACTER) *{sort List -> PathList, op (_:_) -> (_:p_), op nil -> nilP})



  op  dijkstra___ : Character EdgeList EdgeList -> EdgeList
  op exploreNeighbours___  : Character EdgeList  EdgeList -> 4Tuple   {memo}
  ops inf finishedI : -> Int
  op finishedC : -> Character
  op currDist__ :  Character EdgeList -> Int   
  op relax__ : EdgeList EdgeList -> EdgeList   
  op connectedTo__ : Character EdgeList -> Bool 
  op nextNode2Explore_ : EdgeList -> 4Tuple   
  op connectedList___ :  EdgeList Character EdgeList  -> EdgeList  
  op unvisitedList__ :  EdgeList  EdgeList  -> EdgeList  
  op SP___ :  Character Character  EdgeList -> PathList 


  vars  eD pD eD1 pD1 eD2 pD2 source   : Int
  vars graph permanent  xs  : EdgeList
  vars t t1 t2  : 4Tuple
  vars s f z startVertex currentVertex : Character

    
  eq inf = 500 .
  eq finishedI = -1 .
  eq finishedC = 'X' .

-- Main dijkstra function
eq dijkstra startVertex graph permanent =
 if  
(exploreNeighbours startVertex permanent graph)  == << finishedC ;  finishedC ; finishedI ; finishedI >> 
then  permanent
else  
(dijkstra  startVertex graph ( ((exploreNeighbours startVertex permanent graph) :e  permanent))) fi .

  
eq exploreNeighbours startVertex permanent graph = 
(nextNode2Explore (relax (unvisitedList (connectedList graph startVertex permanent)  permanent)  permanent )) .



-- nextNode2Explore takes a list of records and returns a record with the minimum 4th element else finished
eq nextNode2Explore nilE = << finishedC ; finishedC ; finishedI ; finishedI >> .
eq nextNode2Explore (t1 :e nilE) =  t1 . 
eq nextNode2Explore (t2 :e (t1 :e xs)) =  if (4* t1) < (4* t2) then t1 
                                          else  
                                          nextNode2Explore (t2 :e xs) fi .

-- relaxes all edges leaving y
eq relax nilE permanent = nilE .
  eq relax (<< s ; f ; eD ; pD >>  :e xs) permanent =  
if 
(currDist s permanent)  < pD 
then
<< f ; s ; eD ; ((currDist s permanent) + eD)  >> :e (relax xs permanent) 
else
<< f ; s ; eD ; pD  >> :e (relax xs permanent) fi .  


-- Get the current best distance for a particular vertex s. 
eq currDist s nilE  =  inf .
eq currDist s (t :e permanent) =  if ((1* t) == s) then  (4* t ) else 
 (currDist s permanent) fi . 


eq connectedTo z nilE = false .
eq connectedTo z ((<< s ; f ; eD ; pD >>) :e  xs) =  if (s == z) then true else (connectedTo z xs) fi .

eq connectedList nilE s permanent = nilE .     
eq connectedList (t :e graph) s permanent = if (connectedTo s permanent) then
                                           (t :e (connectedList graph s permanent))
                                           else (connectedList graph s permanent) fi  .


eq unvisitedList nilE permanent = nilE .     
eq unvisitedList (t :e  graph) permanent  = if  not(connectedTo (2* t) permanent) 
                                         then (t :e (unvisitedList graph permanent)) 
                                        else (unvisitedList graph permanent) fi  .



-- To get the shortest path from a start node to some end node we used the above dijkstra function.
-- From a given start to a given end we need to trace the path from the finish to the start and then reverse the output.
var eList : EdgeList 
vars currentTuple :   4Tuple
vars  start end :   Character
eq SP start end nilE  = nilP .
eq SP start end (currentTuple :e eList) =  if (end == (1* currentTuple))  then 
                                         (end :p (SP start (2* currentTuple) eList))
                                          else  (SP start end  eList) fi .


-- The graph to be traversed
op  DirectedRosetta  : -> EdgeList
eq DirectedRosetta  =  ( <<  'a' ;  'b' ; 7  ; inf >>  :e
			 <<  'a' ;  'c'  ; 9  ; inf >>  :e
			 <<  'a' ; 'f' ; 14 ; inf >> :e
			 <<  'b' ; 'c' ; 10 ; inf >> :e
			 <<  'b' ;  'd' ; 15 ; inf >> :e
			 <<  'c' ; 'd' ; 11 ; inf >> :e
			 <<  'c' ; 'f'  ; 2  ; inf >> :e
			 <<  'd'  ; 'e' ; 6  ; inf  >> :e
			 <<  'e'  ; 'f'  ; 9  ; inf >>) .
  

  -- A set of possible starting points
  ops  oneStart twoStart threeStart fourStart fiveStart sixStart : -> 4Tuple
  eq oneStart =  <<  'a' ;  'a' ; 0 ; 0 >> .
  eq twoStart = << 'b' ; 'b' ; 0 ; 0 >> .
  eq threeStart = <<  'c' ;  'c' ; 0 ; 0 >> .
  eq fourStart = << 'd' ; 'd' ; 0 ; 0 >> .
  eq fiveStart = <<  'e' ;  'e' ; 0 ; 0 >> .
  eq sixStart  = << 'f' ; 'f' ; 0 ; 0 >> .

} -- End module

-- We must open the module in the CafeOBJ interpreter
open DIJKSTRA .
--> All shortest distances starting from a(1)
red dijkstra 'a' DirectedRosetta oneStart .
-- Gives, where :e is the edge list separator
-- << 'e' ; 'd' ; 6 ; 26 >> :e << 'd' ; 'c' ; 11 ; 20 >> :e << 'f' ; 'c' ; 2 ; 11 >> :e << 'c' ; 'a' ; 9 ; 9 >> :e << 'b' ; 'a' ; 7 ; 7 >>) :e << 'a' ; 'a' ; 0 ; 0 >> :EdgeList

--> Shortest path from a(1) to e(5)
red reverse (SP 'a' 'e' (dijkstra 'a' DirectedRosetta oneStart)) .
-- Gives, where :p is the path list separator
-- 'a' :p 'c' :p 'd' :p 'e' :PathList

--> Shortest path from a(1) to f(6)
red reverse (SP 'a' 'f' (dijkstra 'a' DirectedRosetta oneStart)) .
-- Gives, where :p is the path list separator
-- 'a' :p 'c' :p 'f':PathList
eof

Clojure

(declare neighbours
         process-neighbour
         prepare-costs
         get-next-node
         unwind-path
         all-shortest-paths)


;; Main algorithm


(defn dijkstra
  "Given two nodes A and B, and graph, finds shortest path from point A to point B.
  Given one node and graph, finds all shortest paths to all other nodes.

  Graph example: {1 {2 7 3 9 6 14}
                  2 {1 7 3 10 4 15}
                  3 {1 9 2 10 4 11 6 2}
                  4 {2 15 3 11 5 6}
                  5 {6 9 4 6}
                  6 {1 14 3 2 5 9}}
                  ^  ^  ^
                  |  |  |
         node label  |  |
    neighbour label---  |
          edge cost------
  From example in Wikipedia: https://en.wikipedia.org/wiki/Dijkstra's_algorithm
  
  Output example: [20 [1 3 6 5]]
                   ^  ^
                   |  |
  shortest path cost  |
       shortest path---"
  ([a b graph]
   (loop [costs (prepare-costs a graph)
          unvisited (set (keys graph))]
     (let [current-node (get-next-node costs unvisited)
           current-cost (first (costs current-node))]
       (cond (nil? current-node)
             (all-shortest-paths a costs)

             (= current-node b)
             [current-cost (unwind-path a b costs)]
             
             :else
             (recur (reduce (partial process-neighbour
                                     current-node
                                     current-cost)
                            costs
                            (filter (comp unvisited first)
                                    (neighbours current-node graph costs)))
                    (disj unvisited current-node))))))
  ([a graph] (dijkstra a nil graph)))


;; Implementation details


(defn prepare-costs
  "For given start node A ang graph prepare map of costs to start with
  (assign maximum value for all nodes and zero for starting one).
  Also save info about most advantageous parent.
  Example output: {2 [2147483647 7], 6 [2147483647 14]}
                   ^   ^         ^
                   |   |         |
                node   |         |
               cost-----         |
             parent---------------"
  [start graph]
  (assoc (zipmap (keys graph)
                 (repeat [Integer/MAX_VALUE nil]))
         start [0 start]))


(defn neighbours
  "Get given node's neighbours along with their own costs and costs of corresponding edges.
  Example output is: {1 [7 10] 2 [4 15]}
                      ^  ^  ^
                      |  |  |
   neighbour node label  |  |
        neighbour cost ---  |
             edge cost ------"  
  [node graph costs]
  (->> (graph node)
       (map (fn [[neighbour edge-cost]]
              [neighbour [(first (costs neighbour)) edge-cost]]))
       (into {})))


(defn process-neighbour
  [parent
   parent-cost
   costs
   [neighbour [old-cost edge-cost]]]
  (let [new-cost (+ parent-cost edge-cost)]
    (if (< new-cost old-cost)
      (assoc costs
             neighbour
             [new-cost parent])
      costs)))


(defn get-next-node [costs unvisited]
  (->> costs
       (filter (comp unvisited first))
       (sort-by (comp first second))
       ffirst))


(defn unwind-path
  "Restore path from A to B based on costs data"
  [a b costs]
  (letfn [(f [a b costs]
            (when-not (= a b)
              (cons b (f a (second (costs b)) costs))))]
    (cons a (reverse (f a b costs)))))


(defn all-shortest-paths
  "Get shortest paths for all nodes, along with their costs"
  [start costs]
  (let [paths (->> (keys costs)
                   (remove #{start})
                   (map (fn [n] [n (unwind-path start n costs)])))]
    (into (hash-map)
          (map (fn [[n p]]
                 [n [(first (costs n)) p]])
               paths))))


;; Utils


(require '[clojure.pprint :refer [print-table]])


(defn print-solution [solution]
  (print-table
   (map (fn [[node [cost path]]]
          {'node node 'cost cost 'path path})
        solution)))


;; Solutions


;; Task 1. Implement a version of Dijkstra's algorithm that outputs a set of edges depicting the shortest path to each reachable node from an origin.

;; see above


;; Task 2. Run your program with the following directed graph starting at node a.

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

(def rosetta-graph
  '{a {b 7 c 9 f 14}
    b {c 10 d 15}
    c {d 11 f 2}
    d {e 6}
    e {f 9}
    f {}})

(def task-2-solution
  (dijkstra 'a rosetta-graph))

(print-solution task-2-solution)

;; Output:
;; | node | cost |      path |
;; |------+------+-----------|
;; |    b |    7 |     (a b) |
;; |    c |    9 |     (a c) |
;; |    d |   20 |   (a c d) |
;; |    e |   26 | (a c d e) |
;; |    f |   11 |   (a c f) |


;; Task 3. Write a program which interprets the output from the above and use it to output the shortest path from node a to nodes e and f

(print-solution (select-keys task-2-solution '[e f]))

;; Output:
;; | node | cost |      path |
;; |------+------+-----------|
;; |    e |   26 | (a c d e) |
;; |    f |   11 |   (a c f) |

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

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;

struct Neighbor {
    Vertex target;
    Weight weight;
}

alias AdjacencyMap = Neighbor[][Vertex];

pure dijkstraComputePaths(Vertex source, Vertex target, AdjacencyMap adjacencyMap){
    Weight[Vertex] minDistance;
    Vertex[Vertex] previous;

    foreach(v, neighs; adjacencyMap){
        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.
        foreach(n; adjacencyMap.get(u, null)){
            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)];

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

Delphi

A console program written in Delphi 7. It runs from the Windows command prompt.

An infinite distance is here represented by -1, which complicates the code when comparing distances, but ensures that infinity can't be equalled or exceeded by any finite distance.

program Rosetta_Dijkstra_Console;

{$APPTYPE CONSOLE}

uses SysUtils; // for printing the result

// Conventional values (any negative values would do)
const
  INFINITY  = -1;
  NO_VERTEX = -2;

const
  NR_VERTICES = 6;

// DISTANCE_MATRIX[u, v] = length of directed edge from u to v, or -1 if no such edge exists.
// A simple way to represent a directed graph with not many vertices.
const DISTANCE_MATRIX : array [0..(NR_VERTICES - 1), 0..(NR_VERTICES - 1)] of integer
= ((-1,  7,  9, -1, -1, -1),
   (-1, -1, 10, 15, -1, -1),
   (-1, -1, -1, 11, -1,  2),
   (-1, -1, -1, -1,  6, -1),
   (-1, -1, -1, -1, -1,  9),
   (-1, -1, -1, -1, -1, -1));

type TVertex = record
  Distance : integer; // distance from vertex 0; infinity if a path has not yet been found
  Previous : integer; // previous vertex in the path from vertex 0
  Visited  : boolean; // as defined in the algorithm
end;

// For distances x and y, test whether x < y, using the convention that -1 means infinity.
function IsLess( x, y : integer) : boolean;
begin
  result := (x <> INFINITY)
        and ( (y = INFINITY) or (x < y) );
end;

// Main routine
var
  v : array [0..NR_VERTICES - 1] of TVertex; // array of vertices
  c : integer; // index of current vertex
  j : integer; // loop counter
  trialDistance : integer;
  minDistance : integer;
  // Variables for printing the result
  p : integer;
  lineOut : string;
begin
  // Initialize the vertices
  for j := 0 to NR_VERTICES - 1 do begin
    v[j].Distance := INFINITY;
    v[j].Previous := NO_VERTEX;
    v[j].Visited  := false;
  end;

  // Start with vertex 0 as the current vertex
  c := 0;
  v[c].Distance := 0;

  // Main loop of Dijkstra's algorithm
  repeat

    // Work through unvisited neighbours of the current vertex, updating them where possible.
    // "Neighbour" means the end of a directed edge from the current vertex.
    // Note that v[c].Distance is always finite.
    for j := 0 to NR_VERTICES - 1 do begin
      if (not v[j].Visited) and (DISTANCE_MATRIX[c, j] >= 0) then begin
        trialDistance := v[c].Distance + DISTANCE_MATRIX[c, j];
        if IsLess( trialDistance, v[j].Distance) then begin
          v[j].Distance := trialDistance;
          v[j].Previous := c;
        end;
      end;
    end;

    // When all neighbours have been tested, mark the current vertex as visited.
    v[c].Visited := true;

    // The new current vertex is the unvisited vertex with the smallest finite distance.
    // If there is no such vertex, the algorithm is finished.
    c := NO_VERTEX;
    minDistance := INFINITY;
    for j := 0 to NR_VERTICES - 1 do begin
      if (not v[j].Visited) and IsLess( v[j].Distance, minDistance) then begin
        minDistance := v[j].Distance;
        c := j;
      end;
    end;
  until (c = NO_VERTEX);

  // Print the result
  for j := 0 to NR_VERTICES - 1 do begin
    if (v[j].Distance = INFINITY) then begin
      // The algorithm never found a path to v[j]
      lineOut := SysUtils.Format( '%2d: inaccessible', [j]);
    end
    else begin
      // Build up the path of vertices, working backwards from v[j]
      lineOut := SysUtils.Format( '%2d', [j]);
      p := v[j].Previous;
      while (p <> NO_VERTEX) do begin
        lineOut := SysUtils.Format( '%2d --> ', [p]) + lineOut;
        p := v[p].Previous;
      end;
      // Print the path of vertices, preceded by distance from vertex 0
      lineOut := SysUtils.Format( '%2d: distance = %3d, ', [j, v[j].Distance]) + lineOut;
    end;
    WriteLn( lineOut);
  end;
end.
Output:
 0: distance =   0,  0
 1: distance =   7,  0 -->  1
 2: distance =   9,  0 -->  2
 3: distance =  20,  0 -->  2 -->  3
 4: distance =  26,  0 -->  2 -->  3 -->  4
 5: distance =  11,  0 -->  2 -->  5

EasyLang

global con[][] n .
proc read . .
   repeat
      s$ = input
      until s$ = ""
      a = (strcode substr s$ 1 1) - 96
      b = (strcode substr s$ 3 1) - 96
      d = number substr s$ 5 9
      if a > len con[][]
         len con[][] a
      .
      con[a][] &= b
      con[a][] &= d
   .
   con[][] &= [ ]
   n = len con[][]
.
read
#
len cost[] n
len prev[] n
#
proc dijkstra . .
   for i = 2 to len cost[]
      cost[i] = 1 / 0
   .
   len todo[] n
   todo[1] = 1
   repeat
      min = 1 / 0
      a = 0
      for i to len todo[]
         if todo[i] = 1 and cost[i] < min
            min = cost[i]
            a = i
         .
      .
      until a = 0
      todo[a] = 0
      for i = 1 step 2 to len con[a][] - 1
         b = con[a][i]
         c = con[a][i + 1]
         if cost[a] + c < cost[b]
            cost[b] = cost[a] + c
            prev[b] = a
            todo[b] = 1
         .
      .
   .
.
dijkstra
#
func$ gpath nd$ .
   nd = strcode nd$ - 96
   while nd <> 1
      s$ = " -> " & strchar (nd + 96) & s$
      nd = prev[nd]
   .
   return "a" & s$
.
print gpath "e"
print gpath "f"
#
input_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

Emacs Lisp

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

(defun calculate-shortest-path (path-list)
  (let (shortest-path)
    (dolist (path path-list)
      (add-to-list 'shortest-path (list (nth 0 path)
                                        (nth 1 path)
                                        nil
                                        (nth 2 path))
                   't))
    
    (dolist (path path-list)
      (dolist (short-path shortest-path)
        
        (when (equal (nth 0 path) (nth 1 short-path))
          (let ((test-path (list (nth 0 short-path)
                                 (nth 1 path)
                                 (nth 0 path)
                                 (+ (nth 2 path) (nth 3 short-path))))
                is-path-found)
            
            (dolist (short-path1 shortest-path)
              (when (equal (seq-take test-path 2)
                           (seq-take short-path1 2))
                (setq is-path-found 't)
                (when (> (nth 3 short-path1) (nth 3 test-path))
                  (setcdr (cdr short-path1) (cddr test-path)))))
            
            (when (not is-path-found)
              (add-to-list 'shortest-path test-path 't))))))
    
    shortest-path))

(defun find-shortest-route (from to path-list)
  (let ((shortest-path-list (calculate-shortest-path path-list))
        point-list matched-path distance)
    (add-to-list 'point-list to)
    (setq matched-path
          (seq-find (lambda (path) (equal (list from to) (seq-take path 2)))
                    shortest-path-list))
    (setq distance (nth 3 matched-path))
    (while (nth 2 matched-path)
      (add-to-list 'point-list (nth 2 matched-path))
      (setq to (nth 2 matched-path))
      (setq matched-path
            (seq-find (lambda (path) (equal (list from to) (seq-take path 2)))
                      shortest-path-list)))
    (if matched-path
        (progn
          (add-to-list 'point-list from)
          (list 'route point-list 'distance distance))
      nil)))

(format "%S" (find-shortest-route 'a 'e path-list))

outputs:

(route (a c d e) distance 26)

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]).
Output:
$ ./rebar3 eunit
===> Verifying dependencies...
===> Compiling dijkstra
===> Performing EUnit tests...
The total cost was 20 and the path was: [a,c,f,e]
  Test passed.

F#

Dijkstra's algorithm

//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 [])

The Task

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)
Output:
Some [A; C; D; E]
Some [A; C; F]

Forth

Translation of: Commodore BASIC
\ utility routine to increment a variable
: 1+! 1 swap +! ;

\ edge data
variable edge-count
0 edge-count !
create edges
  'a , 'b ,  7 , edge-count 1+!
  'a , 'c ,  9 , edge-count 1+!
  'a , 'f , 14 , edge-count 1+!
  'b , 'c , 10 , edge-count 1+!
  'b , 'd , 15 , edge-count 1+!
  'c , 'd , 11 , edge-count 1+!
  'c , 'f ,  2 , edge-count 1+!
  'd , 'e ,  6 , edge-count 1+!
  'e , 'f ,  9 , edge-count 1+!

\ with accessors
: edge 3 * cells edges + ;
: edge-from   edge ;
: edge-to     edge 1 cells + ;
: edge-weight edge 2 cells + ;

\ vertex data and acccessor
create vertex-names edge-count @ 2 * cells allot
: vertex-name cells vertex-names + ;

variable vertex-count
0 vertex-count !

\ routine to look up a vertex by name
: find-vertex
    -1 swap
    vertex-count @ 0 ?do
        dup i vertex-name @ = if swap drop i swap leave then
    loop
    drop
;

\ routine to add a new vertex name if not found
: add-vertex
    dup find-vertex dup -1 = if 
        swap vertex-count @ vertex-name !
        vertex-count dup @ swap 1+!
        swap drop
    else
        swap
        drop
    then
;

\ routine to add vertices to name table and replace names with indices in edges
: get-vertices
    edge-count @ 0 ?do
        i edge-from @ add-vertex i edge-from !
        i edge-to   @ add-vertex i edge-to   !
    loop
;

\ call it 
get-vertices

\ variables to hold state during algorithm run
create been-visited
vertex-count @ cells allot
: visited cells been-visited + ;

create prior-vertices
vertex-count @ cells allot
: prior-vertex cells prior-vertices + ;

create distances
vertex-count @ cells allot
: distance cells distances + ;

variable origin
variable current-vertex
variable neighbor
variable current-distance
variable tentative
variable closest-vertex
variable minimum-distance
variable vertex

\ call with origin vertex name on stack
: dijkstra ( origin -- )

    find-vertex origin !

    been-visited vertex-count @ cells 0 fill
    prior-vertices vertex-count @ cells -1 fill
    distances vertex-count @ cells -1 fill

    0 origin @ distance !  \ distance to origin is 0

    origin @ current-vertex ! \ current vertex is the origin

    begin 

    edge-count @ 0 ?do
        i edge-from @ current-vertex @ = if \ if edge is from current
            i edge-to @ neighbor !          \ neighbor vertex
            neighbor @ distance @ current-distance !
            current-vertex @ distance @ i edge-weight @ + tentative !
            current-distance @ -1 = tentative @ current-distance @ < or if
                tentative @ neighbor @ distance !
                current-vertex @ neighbor @ prior-vertex !
            then
        else
        then
    loop

    1 current-vertex @ visited ! \ current vertex has now been visited
    -1 closest-vertex !

    vertex-count @ 0 ?do
        i visited @ 0= if 
            -1 minimum-distance !
            closest-vertex @ dup -1 <> if 
                distance @ minimum-distance !
            else
                drop
            then
            i distance @ -1 <> 
                minimum-distance @ -1 = i distance @ minimum-distance @ < or
              and if
                i closest-vertex !
            then
        then
    loop

    closest-vertex @ current-vertex !
    current-vertex @ -1 = until

    cr
    ." Shortest path to each vertex from " origin @ vertex-name @ emit ': emit cr
    vertex-count @ 0 ?do
        i origin @ <> if
            i vertex-name @ emit ." : " i distance @ dup
            -1 = if
                drop
                ." ∞ (unreachable)"
            else
                .
                '( emit
                i vertex !
                begin
                    vertex @ vertex-name @ emit
                    vertex @ origin @ <> while
                        ." "
                        vertex @ prior-vertex @ vertex !
                repeat
                ') emit
            then
            cr
        then
    loop
;
Output:
'a dijkstra 
Shortest path to each vertex from a:
b: 7 (b←a)
c: 9 (c←a)
f: 11 (f←c←a)
d: 20 (d←c←a)
e: 26 (e←d←c←a)
 ok
'b dijkstra 
Shortest path to each vertex from b:
a: ∞ (unreachable)
c: 10 (c←b)
f: 12 (f←c←b)
d: 15 (d←b)
e: 21 (e←d←b)
 ok

Fortran

program main
! Demo of Dijkstra's algorithm.
! Translation of Rosetta code Pascal version
   implicit none
!
! PARAMETER definitions
!
   integer , parameter :: nr_nodes = 6 , start_index = 0
!
! Derived Type definitions
!
   enum , bind(c)
      enumerator :: SetA , SetB , SetC
   end enum
!
   type tnode
      integer :: nodeset
      integer :: previndex ! previous node in path leading to this node
      integer :: pathlength ! total length of path to this node
   end type tnode
!
! Local variable declarations
!
   integer :: branchlength , j , j_min , k , lasttoseta , minlength , nrinseta , triallength
   character(5) :: holder
   integer , dimension(0:nr_nodes - 1 , 0:nr_nodes - 1) :: lengths
   character(132) :: lineout
   type (tnode) , dimension(0:nr_nodes - 1) :: nodes
!   character(2) , dimension(0:nr_nodes - 1) :: node_names
   character(15),dimension(0:nr_nodes-1) :: node_names
!   Correct values
!Shortest paths from node a:
!  b: length   7,  a -> b
!  c: length   9,  a -> c
!  d: length  20,  a -> c -> d
!  e: length  26,  a -> c -> d -> e
!  f: length  11,  a -> c -> f
!
   nodes%nodeset = 0
   nodes%previndex = 0
   nodes%pathlength = 0

   node_names = (/'a' , 'b' , 'c' , 'd' , 'e' , 'f'/)
!
! lengths[j,k] = length of branch j -> k, or -1 if no such branch exists.
   lengths(0 , :) = (/ - 1 , 7 , 9 , -1 , -1 , 14/)
   lengths(1 , :) = (/ - 1 , -1 , 10 , 15 , -1 , -1/)
   lengths(2 , :) = (/ - 1 , -1 , -1 , 11 , -1 , 2/)
   lengths(3 , :) = (/ - 1 , -1 , -1 , -1 , 6 , -1/)
   lengths(4 , :) = (/ - 1 , -1 , -1 , -1 , -1 , 9/)
   lengths(5 , :) = (/ - 1 , -1 , -1 , -1 , -1 , -1/)



   do j = 0 , nr_nodes - 1
      nodes(j)%nodeset = SetC
   enddo
  ! Begin by transferring the start node to set A
   nodes(start_index)%nodeset = SetA
   nodes(start_index)%pathlength = 0
   nrinseta = 1
   lasttoseta = start_index
  ! Transfer nodes to set A one at a time, until all have been transferred
   do while (nrinseta<nr_nodes)
   ! Step 1: Work through branches leading from the node that was most recently
    !        transferred to set A, and deal with end nodes in set B or set C.
    do j = 0 , nr_nodes - 1
         branchlength = lengths(lasttoseta , j)
         if (branchlength>=0) then
        ! If the end node is in set B, and the path to the end node via lastToSetA
        !   is shorter than the existing path, then update the path.
            if (nodes(j)%nodeset==SetB) then
               triallength = nodes(lasttoseta)%pathlength + branchlength
               if (triallength<nodes(j)%pathlength) then
                  nodes(j)%previndex = lasttoseta
                  nodes(j)%pathlength = triallength
               endif
        ! If the end node is in set C, transfer it to set B.
        elseif (nodes(j)%nodeset==SetC) then
               nodes(j)%nodeset = SetB
               nodes(j)%previndex = lasttoseta
               nodes(j)%pathlength = nodes(lasttoseta)%pathlength + branchlength
            endif
         endif
      enddo
! Step 2: Find the node in set B with the smallest path length,
    !         and transfer that node to set A.
    !         (Note that set B cannot be empty at this point.)
      minlength = -1
      j_min = -1
      do j = 0 , nr_nodes - 1
         if (nodes(j)%nodeset==SetB) then
            if ((j_min== - 1).or.(nodes(j)%pathlength<minlength)) then
               j_min = j
               minlength = nodes(j)%pathlength
            endif
         endif
      enddo
      nodes(j_min)%nodeset = SetA
      nrinseta = nrinseta + 1
      lasttoseta = j_min
   enddo

   print* , 'Shortest paths from node ',trim(node_names(start_index))


   do j = 0 , nr_nodes - 1
      if (j/=start_index) then
         k = j
         lineout = node_names(k)
         pete_loop: do
            k = nodes(k)%previndex
            lineout = trim(node_names(k)) // ' -> ' // trim(lineout)
            if (k==start_index) exit pete_loop
         enddo pete_loop
         write (holder , '(i0)') nodes(j)%pathlength
         lineout = trim(adjustl(node_names(j))) // ': length ' // trim(adjustl(holder)) // ', ' // trim(lineout)
         print * , lineout
      endif
   enddo
   stop
end program main
Output:
Shortest paths from node a
 b: length 7, a -> b                                                                                                                 
 c: length 9, a -> c                                                                                                                 
 d: length 20, a -> c -> d                                                                                                           
 e: length 26, a -> c -> d -> e                                                                                                      
 f: length 11, a -> c -> f    

Free Pascal

Requires FPC version of at least 3.2.0.

For convenience, let's try to use priority queue from[[1]].

program SsspDemo;
{$mode delphi}
uses
  SysUtils, Generics.Collections, PQueue;

type
  TArc = record
    Target: string;
    Cost: Integer;
    constructor Make(const t: string; c: Integer);
  end;
  TDigraph = class
  strict private
    FGraph: TObjectDictionary<string, TList<TArc>>;
  public
  const
    INF_WEIGHT = MaxInt;
    constructor Create;
    destructor Destroy; override;
    procedure AddNode(const n: string);
    procedure AddArc(const s, t: string; c: Integer);
    function  AdjacencyList(const n: string): TList<TArc>;
    function  DijkstraSssp(const From: string; out PathTree: TDictionary<string, string>;
                           out Dist: TDictionary<string, Integer>): Boolean;
  end;

constructor TArc.Make(const t: string; c: Integer);
begin
  Target := t;
  Cost := c;
end;

function CostCmp(const L, R: TArc): Boolean;
begin
  Result := L.Cost > R.Cost;
end;

constructor TDigraph.Create;
begin
  FGraph := TObjectDictionary<string, TList<TArc>>.Create([doOwnsValues]);
end;

destructor TDigraph.Destroy;
begin
  FGraph.Free;
  inherited;
end;

procedure TDigraph.AddNode(const n: string);
begin
  if not FGraph.ContainsKey(n) then
    FGraph.Add(n, TList<TArc>.Create);
end;

procedure TDigraph.AddArc(const s, t: string; c: Integer);
begin
  AddNode(s);
  AddNode(t);
  if s <> t then
    FGraph.Items[s].Add(TArc.Make(t, c));
end;

function TDigraph.AdjacencyList(const n: string): TList<TArc>;
begin
  if not FGraph.TryGetValue(n, Result) then
    Result := nil;
end;

function TDigraph.DijkstraSssp(const From: string; out PathTree: TDictionary<string, string>;
  out Dist: TDictionary<string, Integer>): Boolean;
var
  q: TPriorityQueue<TArc>;
  Reached: THashSet<string>;
  Handles: TDictionary<string, q.THandle>;
  Next, Arc, Relax: TArc;
  h: q.THandle = -1;
  k: string;
begin
  if not FGraph.ContainsKey(From) then exit(False);
  Reached := THashSet<string>.Create;
  Handles := TDictionary<string, q.THandle>.Create;
  Dist := TDictionary<string, Integer>.Create;
  for k in FGraph.Keys do
    Dist.Add(k, INF_WEIGHT);
  PathTree := TDictionary<string, string>.Create;
  q := TPriorityQueue<TArc>.Create(@CostCmp);
  PathTree.Add(From, '');
  Next := TArc.Make(From, 0);
  repeat
    Reached.Add(Next.Target);
    Dist[Next.Target] := Next.Cost;
    for Arc in AdjacencyList(Next.Target) do
      if not Reached.Contains(Arc.Target)then
        if Handles.TryGetValue(Arc.Target, h) then begin
          Relax := q.GetValue(h);
          if Arc.Cost + Next.Cost < Relax.Cost then begin
            q.Update(h, TArc.Make(Relax.Target, Arc.Cost + Next.Cost));
            PathTree[Arc.Target] := Next.Target;
          end
        end else begin
          Handles.Add(Arc.Target, q.Push(TArc.Make(Arc.Target, Arc.Cost + Next.Cost)));
          PathTree.Add(Arc.Target, Next.Target);
        end;
  until not q.TryPop(Next);
  Reached.Free;
  Handles.Free;
  q.Free;
  Result := True;
end;

function ExtractPath(PathTree: TDictionary<string, string>; n: string): TStringArray;
begin
  if not PathTree.ContainsKey(n) then exit(nil);
  with TList<string>.Create do begin
    repeat
      Add(n);
      n := PathTree[n];
    until n = '';
    Reverse;
    Result := ToArray;
    Free;
  end;
end;

const
  PathFmt = 'shortest path from "%s" to "%s": %s (cost = %d)';
var
  g: TDigraph;
  Path: TDictionary<string, string>;
  Dist: TDictionary<string, Integer>;
begin
  g := TDigraph.Create;
  g.AddArc('a', 'b',  7); g.AddArc('a', 'c',  9); g.AddArc('a', 'f', 14);
  g.AddArc('b', 'c', 10); g.AddArc('b', 'd', 15); g.AddArc('c', 'd', 11);
  g.AddArc('c', 'f',  2); g.AddArc('d', 'e',  6); g.AddArc('e', 'f',  9);
  g.DijkstraSssp('a', Path, Dist);
  WriteLn(Format(PathFmt, ['a', 'e', string.Join('->', ExtractPath(Path, 'e')), Dist['e']]));
  WriteLn(Format(PathFmt, ['a', 'f', string.Join('->', ExtractPath(Path, 'f')), Dist['f']]));
  g.Free;
  Path.Free;
  Dist.Free;
  readln;
end.
Output:
shortest path from "a" to "e": a->c->d->e (cost = 26)
shortest path from "a" to "f": a->c->f (cost = 11)

Go

package main

import (
	"container/heap"
	"fmt"
)

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

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) {
	vs := g.Vertices()
	dist = make(map[Vertex]int, len(vs))
	prev = make(map[Vertex]Vertex, len(vs))
	sid := source
	dist[sid] = 0
	q := &PriorityQueue{
		items: make([]Vertex, 0, len(vs)),
		m:     make(map[Vertex]int, len(vs)),
		pr:    make(map[Vertex]int, len(vs)),
	}
	for _, v := range vs {
		if v != sid {
			dist[v] = Infinity
		}
		prev[v] = Uninitialized
		q.addWithPriority(v, dist[v])
	}
	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, len(ids))
	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() []Vertex {
	vs := make([]Vertex, 0, len(g.ids))
	for _, v := range g.ids {
		vs = append(vs, v)
	}
	return vs
}
func (g sg) Neighbors(u Vertex) []Vertex {
	vs := make([]Vertex, 0, len(g.edges[u]))
	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))
}

Runable on the Go playground.

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

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.

{-# LANGUAGE FlexibleContexts #-}
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  -- note that aux is being called within its own definition (i.e. aux is recursive). The foldM only iterates on the neighbours of v, it does not execute the while loop itself in Dijkstra's
  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

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 = [];
	add_node( name_ ) {
		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[0] ) ) {
		line = input();
		if ( line == none ) {
			return ( 1 );
		}
		g.add_node( line.strip() );
	}
	for ( _ : algo.range( conf[1] ) ) {
		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]

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

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
)

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
┌─────────┐
│┌─┬─┬─┬─┐│
││acde││
│└─┴─┴─┴─┘│
└─────────┘

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 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;
         q.add(v);
      }
      
      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;
               q.add(v);
            } 
         }
      }
   }
   
   /** 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();
      }
   }
}
Output:

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 = {},
          adj = {}

    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][0], 
            v2 = edges[i][1],
            len = edges[i][2]

        Q.add(v1)
        Q.add(v2)

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

        if (adj[v1] === undefined) adj[v1] = {}
        if (adj[v2] === undefined) adj[v2] = {}

        adj[v1][v2] = len
        adj[v2][v1] = len
    }
     
    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])
            len += adj[u][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

jq

Works with: jq

Works with gojq, the Go implementation of jq (*)

For this entry, the graph will be represented by a JSON object with keys, $k, such that `.[$k]` describes the immediate neighbors of node $k, with `.[$k][$n]` being the distance from node $k to node $n. A JSON object of this form will be referred to as a Graph.

Not all nodes of the graph need be top-level keys of the graph object.

The function `dijkstra($startname)` fulfills the first part of the task. It produces the final state of a "scratchpad" in the form of a JSON object with key:value pairs of the form `node: {prev, dist}`. In its final state, `dist` is the shortest distance from the node identified by the key to the node identified by `node`. The `readout` function is the function envisioned by the third part of the task.

Preliminaries

# (*) If using gojq, uncomment the following line:
# def keys_unsorted: keys;

# remove the first occurrence of $x from the input array
def rm($x):
  index($x) as $ix
  | if $ix then .[:$ix] + .[$ix+1:] else . end;

# Input: a Graph
# Output: a (possibly empty) stream of the neighbors of $node 
# that are also in the array $ary
def neighbors($node; $ary:
  .[$node]
  | select(.)
  | keys_unsorted[]
  | . as $n
  | select($ary | index($n));

# Input: a Graph
def vertices:
  [keys_unsorted[], (.[] | keys_unsorted[])] | unique;
  
# Input: a Graph
# Output: the final version of the scratchpad
def dijkstra($startname):
  . as $graph
  | vertices as $Q
  # scratchpad: { node: { prev, dist} }
  | reduce $Q[] as $v ({};
      . + { ($v): {prev: null, dist: infinite}} )
  | .[$startname].dist = 0
  | { scratchpad: ., $Q }
  | until( .Q|length == 0;
      .scratchpad as $scratchpad
      | ( .Q | min_by($scratchpad[.].dist)) as $u
      | .Q |= rm($u)
      | .Q as $Q
      # for each neighbor v of u still in Q:
      | reduce ($graph|neighbors($u; $Q)) as $v (.;
              (.scratchpad[$u].dist + $graph[$u][$v]) as $alt
              | if $alt < .scratchpad[$v].dist
                then .scratchpad[$v].dist = $alt
                | .scratchpad[$v].prev = $u
		else . end ) )
  | .scratchpad ;	

# Input: a Graph
# Output: the scratchpad
def Dijkstra($startname):
  if .[$startname] == null then "The graph does not contain start vertex \(startname)"
  else dijkstra($startname)
  end;

# Input: scratchpad, i.e. a dictionary with key:value pairs of the form:
#   node: {prev, dist}
# Output: an array, being
#   [optimal path from $node to $n, optimal distance from $node to $n]
def readout($node):
  . as $in
  | $node
  | [recurse($in[.].prev; .)]
  | [reverse, $in[$node].dist] ;

# Input: a graph
# Output: [path, value]
def Dijkstra($startname; $endname):
  Dijkstra($startname)
  | readout($endname) ;

The Task

def GRAPH: {
   "a": {"b": 7, "c": 9, "f": 14},
   "b": {"c": 10, "d": 15},
   "c": {"d": 11, "f": 2},
   "d": {"e": 6},
   "e": {"f": 9}
  };

# To produce the final version of the scratchpad:
# GRAPH | Dijkstra("a")

"\nThe shortest paths from a to e and to f:",
(GRAPH | Dijkstra("a"; "e", "f") | .[0])
Output:
The shortest paths from a to e and to f:
["a","c","d","e"]
["a","c","f"]


Julia

Works with: Julia version 1.8
using Printf

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[1], edge[2]) => edge[3] for edge in edges)
    return Digraph(adjmat, vnames)
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
            pushfirst!(rst, dest)
            dest = prev[dest]
        end
        pushfirst!(rst, dest)
        return rst, cost
    end
end

# testgraph = [("a", "b", 1), ("b", "e", 2), ("a", "e", 4)]
const 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)]

function testpaths()
    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
end

testpaths()
Output:
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

Translation of: 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
            q.add(v)
        }

        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
                    q.add(v)
                }
            }
        }
    }

    /** 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)
    }
}
Output:
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
function follow (trail, destination)
    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))
Output:
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
Output:
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

Maple

restart:
with(GraphTheory):
G:=Digraph([a,b,c,d,e,f],{[[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]}):
DijkstrasAlgorithm(G,a);
# [[[a], 0], [[a, b], 7], [[a, c], 9], [[a, c, d], 20], [[a, c, d, e], 26], [[a, c, f], 11]]

Mathematica /Wolfram Language

bd = Graph[{"a" \[DirectedEdge] "b", "a" \[DirectedEdge] "c", 
   "b" \[DirectedEdge] "c", "b" \[DirectedEdge] "d", 
   "c" \[DirectedEdge] "d", "d" \[DirectedEdge] "e", 
   "a" \[DirectedEdge] "f", "c" \[DirectedEdge] "f", 
   "e" \[DirectedEdge] "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", "d", "e"}

File:Mma dijkstra2.PNG

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

Nim

Translation of Wikipedia pseudo-code.

# Dijkstra algorithm.

from algorithm import reverse
import sets
import strformat
import tables

type
  Edge = tuple[src, dst: string; cost: int]
  Graph = object
    vertices: HashSet[string]
    neighbours: Table[string, seq[tuple[dst: string, cost: float]]]

#---------------------------------------------------------------------------------------------------

proc initGraph(edges: openArray[Edge]): Graph =
  ## Initialize a graph from an edge list.
  ## Use floats for costs in order to compare to Inf value.

  for (src, dst, cost) in edges:
    result.vertices.incl(src)
    result.vertices.incl(dst)
    result.neighbours.mgetOrPut(src, @[]).add((dst, cost.toFloat))

#---------------------------------------------------------------------------------------------------

proc dijkstraPath(graph: Graph; first, last: string): seq[string] =
  ## Find the path from "first" to "last" which minimizes the cost.

  var dist = initTable[string, float]()
  var previous = initTable[string, string]()
  var notSeen = graph.vertices
  for vertex in graph.vertices:
    dist[vertex] = Inf
  dist[first] = 0

  while notSeen.card > 0:
    # Search vertex with minimal distance.
    var vertex1: string
    var mindist = Inf
    for vertex in notSeen:
      if dist[vertex] < mindist:
        vertex1 = vertex
        mindist = dist[vertex]
    if vertex1 == last:
      break
    notSeen.excl(vertex1)
    # Find shortest paths to neighbours.
    for (vertex2, cost) in graph.neighbours.getOrDefault(vertex1):
      if vertex2 in notSeen:
        let altdist = dist[vertex1] + cost
        if altdist < dist[vertex2]:
          # Found a shorter path to go to vertex2.
          dist[vertex2] = altdist
          previous[vertex2] = vertex1    # To go to vertex2, go through vertex1.

  # Build the path.
  var vertex = last
  while vertex.len > 0:
    result.add(vertex)
    vertex = previous.getOrDefault(vertex)
  result.reverse()

#---------------------------------------------------------------------------------------------------

proc printPath(path: seq[string]) =
  ## Print a path.
  stdout.write(fmt"Shortest path from '{path[0]}' to '{path[^1]}': {path[0]}")
  for i in 1..path.high:
    stdout.write(fmt" → {path[i]}")
  stdout.write('\n')

#---------------------------------------------------------------------------------------------------

let graph = initGraph([("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)])
printPath(graph.dijkstraPath("a", "e"))
printPath(graph.dijkstraPath("a", "f"))
Output:
Shortest path from 'a' to 'e': a → c → d → e
Shortest path from 'a' to 'f': a → c → f

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

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

Pascal

Classic algorithm like this has to have a Pascal implementation...

program dijkstra(output);

type
  { We dynamically build the list of vertices from the edge list,
    just to avoid repeating ourselves in the graph input. Vertices are linked
    together via their `next` pointers to form a list of all vertices (sorted by
    name), while the `previous` pointer indicates the previous vertex along the
    shortest path to this one. }
  vertex = record
    name: char;
    visited: boolean;
    distance: integer;
    previous: ^vertex;
    next: ^vertex;
  end;

  vptr = ^vertex;

  { The graph is specified as an array of these }
  edge_desc = record
    source: char;
    dest: char;
    weight: integer;
  end;

const
  { the input graph }
  edges:    array of edge_desc = (
    (source:'a'; dest:'b'; weight:7),
    (source:'a'; dest:'c'; weight:9),
    (source:'a'; dest:'f'; weight:14),
    (source:'b'; dest:'c'; weight:10),
    (source:'b'; dest:'d'; weight:15),
    (source:'c'; dest:'d'; weight:11),
    (source:'c'; dest:'f'; weight:2),
    (source:'d'; dest:'e'; weight:6),
    (source:'e'; dest:'f'; weight:9)
  );

  { find the shortest path to all nodes starting from this one }
  origin: char = 'a';

var
  head_vertex: vptr = nil;
  curr, next, closest: vptr;
  vtx: vptr;
  dist: integer;
  edge: edge_desc;
  done: boolean = false;

{ allocate a new vertex node with the given name and `next` pointer }
function new_vertex(key: char; next: vptr): vptr;

  var
    vtx: vptr;
  begin
    new(vtx);
    vtx^.name := key;
    vtx^.visited := false;
    vtx^.distance := maxint;
    vtx^.previous := nil;
    vtx^.next := next;
    new_vertex := vtx;
  end;


{ look up a vertex by name; create it if needed }
function find_or_make_vertex(key: char): vptr; var
    vtx, prev, found: vptr;
    done: boolean;

  begin

    found := nil;
    if head_vertex = nil then
      head_vertex := new_vertex(key, nil)
    else if head_vertex^.name > key then
      head_vertex := new_vertex(key, head_vertex);

    if head_vertex^.name = key then
      found := head_vertex
    else begin
      prev := head_vertex;
      vtx := head_vertex^.next;
      done := false;
      while not done do
        if vtx = nil then
          done := true
        else if vtx^.name >= key then
          done := true
        else begin
          prev := vtx;
          vtx := vtx^.next
        end;
      if vtx <> nil then
        if vtx^.name = key then
          found := vtx;
      if found = nil then begin
        prev^.next := new_vertex(key, vtx);
        found := prev^.next;
      end
    end;
    find_or_make_vertex := found
  end;

{ display the path to a vertex indicated by its `previous` pointer chain }
procedure write_path(vtx: vptr);
  begin
    if vtx <> nil then begin
      if vtx^.previous <> nil then begin
        write_path(vtx^.previous);
        write('→');
      end;
      write(vtx^.name);
    end;
  end;

begin
  curr := find_or_make_vertex(origin);
  curr^.distance := 0;
  curr^.previous := nil;
  while not done do begin
    for edge in edges do begin
      if edge.source = curr^.name then begin
        next := find_or_make_vertex(edge.dest);
        dist := curr^.distance + edge.weight;
        if dist < next^.distance then begin
           next^.distance := dist;
           next^.previous := curr;
        end
      end
    end;
    curr^.visited := true;
    closest := nil;
    vtx := head_vertex;
    while vtx <> nil do begin
      if not vtx^.visited then
        if closest = nil then
          closest := vtx
        else if vtx^.distance < closest^.distance then
          closest := vtx;
      vtx := vtx^.next;
    end;
    if closest = nil then
      done := true
    else if closest^.distance = maxint then
      done := true;
    curr := closest;
  end;
  writeln('Shortest path to each vertex from ', origin, ':');
  vtx := head_vertex;
  while vtx <> nil do begin
    write(vtx^.name, ':', vtx^.distance);
    if vtx^.distance > 0 then begin
      write(' (');
      write_path(vtx);
      write(')');
    end;
    writeln();
    vtx := vtx^.next;
  end
end.
Output:
Shortest path to each vertex from a:
a:0
b:7 (a→b)
c:9 (a→c)
d:20 (a→c→d)
e:26 (a→c→d→e)
f:11 (a→c→f)

Pascal (alternative)

This alternative Pascal version is based directly on Dijkstra's 1959 paper. It was written independently of the VBA version, q.v. for references and for the algorithm in Dijkstra's own words.

The problem as stated by Dijkstra is to find the shortest path from a given node P to a given node Q. A common variant, which is implemented here and requires only a small change in the algorithm, is to find the shortest path from P to every other node.

Dijkstra divides the nodes into three sets A, B, and C. Nodes in set C have no path length assigned yet; nodes in set B have a provisional path length; nodes in set A have a final path length. As the algorithm proceeds, nodes are transferred from C to B to A. The algorithm stops when Q has been transferred to A (in the original problem) or when all nodes have been transferred to A (in the variant). Nodes in set A are called "visited" in many descriptions of the algorithm.

The original paper also has a division of the branches (edges) into three sets I, II, and III, but the program posted here does not make use of these.

Almost every online description of the algorithm introduces the concept of infinite path length. There is no mention of this in Dijkstra's paper, and it doesn't seem to be necessary.

program Dijkstra_console;
// Demo of Dijkstra's algorithm.
// Free Pascal (Lazarus), console application.

uses SysUtils;
type
  TNodeSet = (setA, setB, setC);
  TNode = record
    NodeSet : TNodeSet;
    PrevIndex : integer;  // previous node in path leading to this node
    PathLength : integer; // total length of path to this node
  end;

const
// Rosetta code task
  NR_NODES = 6;
  START_INDEX = 0;
  NODE_NAMES: array [0..NR_NODES - 1] of string = ('a','b','c','d','e','f');
  // LENGTHS[j,k] = length of branch j -> k, or -1 if no such branch exists.
  LENGTHS : array [0..NR_NODES - 1] of array [0..NR_NODES - 1] of integer
  = ((-1, 7, 9,-1,-1,14),
     (-1,-1,10,15,-1,-1),
     (-1,-1,-1,11,-1, 2),
     (-1,-1,-1,-1, 6,-1),
     (-1,-1,-1,-1,-1, 9),
     (-1,-1,-1,-1,-1,-1));

var
  nodes : array [0..NR_NODES - 1] of TNode;
  j, j_min, k : integer;
  lastToSetA, nrInSetA: integer;
  branchLength, trialLength, minLength : integer;
  lineOut : string;
begin
  // Initialize nodes: all in set C
  for j := 0 to NR_NODES - 1 do begin
    nodes[j].NodeSet := setC;
    // No need to initialize PrevIndex and PathLength, as they are
    //   not used until a value has been assigned by the algorithm.
  end;

  // Begin by transferring the start node to set A
  nodes[START_INDEX].NodeSet := setA;
  nodes[START_INDEX].PathLength := 0;
  nrInSetA := 1;
  lastToSetA := START_INDEX;

  // Transfer nodes to set A one at a time, until all have been transferred
  while (nrInSetA < NR_NODES) do begin

    // Step 1: Work through branches leading from the node that was most recently
    //         transferred to set A, and deal with end nodes in set B or set C.
    for j := 0 to NR_NODES - 1 do begin
      branchLength := LENGTHS[ lastToSetA, j];
      if (branchLength >= 0) then begin
        // If the end node is in set B, and the path to the end node via lastToSetA
        //   is shorter than the existing path, then update the path.
        if (nodes[j].NodeSet = setB) then begin
          trialLength := nodes[lastToSetA].PathLength + branchLength;
          if (trialLength < nodes[j].PathLength) then begin
            nodes[j].PrevIndex := lastToSetA;
            nodes[j].PathLength := trialLength;
          end;
        end
        // If the end node is in set C, transfer it to set B.
        else if (nodes[j].NodeSet = setC) then begin
          nodes[j].NodeSet := setB;
          nodes[j].PrevIndex := lastToSetA;
          nodes[j].PathLength := nodes[lastToSetA].PathLength + branchLength;
        end;
      end;
    end;

    // Step 2: Find the node in set B with the smallest path length,
    //         and transfer that node to set A.
    //         (Note that set B cannot be empty at this point.)
    minLength := -1; // just to stop compiler warning "might not have been initialized"
    j_min := -1; // index of node with smallest path length; will become >= 0
    for j := 0 to NR_NODES - 1 do begin
      if (nodes[j].NodeSet = setB) then begin
        if (j_min < 0) or (nodes[j].PathLength < minLength) then begin
          j_min := j;
          minLength := nodes[j].PathLength;
        end;
      end;
    end;
    nodes[j_min].NodeSet := setA;
    inc( nrInSetA);
    lastToSetA := j_min;
  end;

  // Write result to console
  WriteLn( SysUtils.Format( 'Shortest paths from node %s:', [NODE_NAMES[START_INDEX]]));
  for j := 0 to NR_NODES - 1 do begin
    if (j <> START_INDEX) then begin
      k := j;
      lineOut := NODE_NAMES[k];
      repeat
        k := nodes[k].PrevIndex;
        lineOut := NODE_NAMES[k] + ' -> ' + lineOut;
      until (k = START_INDEX);
      lineOut := SysUtils.Format( '%3s: length %3d,  ',
                 [NODE_NAMES[j], nodes[j].PathLength]) + lineOut;
      WriteLn( lineOut);
    end;
  end;
end.
Output:
Shortest paths from node a:
  b: length   7,  a -> b
  c: length   9,  a -> c
  d: length  20,  a -> c -> d
  e: length  26,  a -> c -> d -> e
  f: length  11,  a -> c -> f

Perl

use strict;
use warnings;
use constant True => 1;

sub add_edge {
    my ($g, $a, $b, $weight) = @_;
    $g->{$a} ||= {name => $a};
    $g->{$b} ||= {name => $b};
    push @{$g->{$a}{edges}}, {weight => $weight, vertex => $g->{$b}};
}

sub push_priority {
    my ($a, $v) = @_;
    my $i = 0;
    my $j = $#{$a};
    while ($i <= $j) {
        my $k = int(($i + $j) / 2);
        if ($a->[$k]{dist} >= $v->{dist}) { $j = $k - 1 }
        else                              { $i = $k + 1 }
    }
    splice @$a, $i, 0, $v;
}

sub dijkstra {
    my ($g, $a, $b) = @_;
    for my $v (values %$g) {
        $v->{dist} = 10e7; # arbitrary large value
        delete @$v{'prev', 'visited'}
     }
    $g->{$a}{dist} = 0;
    my $h = [];
    push_priority($h, $g->{$a});
    while () {
        my $v = shift @$h;
        last if !$v or $v->{name} eq $b;
        $v->{visited} = True;
        for my $e (@{$v->{edges}}) {
            my $u = $e->{vertex};
            if (!$u->{visited} && $v->{dist} + $e->{weight} <= $u->{dist}) {
                $u->{prev} = $v;
                $u->{dist} = $v->{dist} + $e->{weight};
                push_priority($h, $u);
            }
        }
    }
}

my $g = {};
add_edge($g, @$_) for
 (['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($g, 'a', 'e');

my $v = $g->{e};
my @a;
while ($v) {
    push @a, $v->{name};
    $v = $v->{prev};
}
my $path = join '', reverse @a;
print "$g->{e}{dist} $path\n";
Output:
26 acde

Phix

I didn't really copy any other code/pseudocode, just followed the basic concept of (update costs) (select lowest cost unvisited) until target reached.
Selects the shortest path from A to B only. As for time complexity, it looks plenty efficient enough to me, though it clearly is O(V^2).
Written after the task was changed to be a directed graph, and shows the correct solution for that.

with javascript_semantics
--requires("1.0.2") -- (builtin E renamed as EULER)
--enum A,B,C,D,E,F
constant A=1, B=2, C=3, D=4, E=5, F=6 -- (or use this)
constant 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}}
 
sequence visited,
         cost,
         from
 
procedure reset()
    visited = repeat(0,6)
    cost = repeat(0,6)
    from = repeat(0,6)
end procedure
 
function backtrack(integer finish,start)
    sequence res = {finish}
    while finish!=start do
        finish = from[finish]
        res = prepend(res,finish)
    end while
    return res
end function
 
function shortest_path(integer start, integer finish)
    integer estart, eend, ecost, ncost, mincost
    while 1 do
        visited[start] = 1
        for i=1 to length(edges) do
            {estart,eend,ecost} = edges[i]
            if estart=start then
                ncost = cost[start]+ecost
                if visited[eend]=0 then
                    if from[eend]=0
                    or cost[eend]>ncost then
                        cost[eend] = ncost
                        from[eend] = start
                    end if
                elsif cost[eend]>ncost then
                    ?9/0    -- sanity check
                end if
            end if
        end for
        mincost = 0
        for i=1 to length(visited) do
            if visited[i]=0 
            and from[i]!=0 then
                if mincost=0
                or cost[i]<mincost then
                    start = i
                    mincost = cost[start]
                end if
            end if
        end for
        if visited[start] then return -1 end if
        if start=finish then return cost[finish] end if
    end while
end function
 
function AFi(integer i)     -- output helper
    return 'A'+i-1
end function
 
procedure test(sequence testset)
    integer start, finish, ecost, len
    string epath, path
    for i=1 to length(testset) do
        {start,finish,ecost,epath} = testset[i]
        reset()
        len = shortest_path(start,finish)
        path = iff(len=-1?"no path found":join(apply(backtrack(finish,start),AFi),""))
        printf(1,"%c->%c: length %d:%s (expected %d:%s)\n",{AFi(start),AFi(finish),len,path,ecost,epath})
    end for
end procedure
 
test({{A,E,26,"ACDE"},{A,F,11,"ACF"},{F,A,-1,"none"}})
Output:
A->E: length 26:ACDE (expected 26:ACDE)
A->F: length 11:ACF (expected 11:ACF)
F->A: length -1:no path found (expected -1:none)

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]);
        $neighbours[$edge[1]][] = array("end" => $edge[0], "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, f, e

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

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.

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, deque
from pprint import pprint as pp
 
 
inf = float('inf')
Edge = namedtuple('Edge', ['start', 'end', 'cost'])
 
class Graph():
    def __init__(self, edges):
        self.edges = [Edge(*edge) for edge in edges]
        # print(dir(self.edges[0]))
        self.vertices = {e.start for e in self.edges} | {e.end for e in self.edges}
 
    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))
            neighbours[end].add((start, cost))

        #pp(neighbours)
 
        while q:
            # pp(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 = deque(), dest
        while previous[u]:
            s.appendleft(u)
            u = previous[u]
        s.appendleft(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:
deque(['a', 'c', 'f', 'e'])

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)

Raku

(formerly Perl 6)

Works with: Rakudo version 2018.03
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) {