Java : Dijkstra's Algorithm

  • Dijkstra’s algorithm finds the shortest path in a weighted graph from a single source.

  • The weighted graph for Dijkstra’s algorithm contains only positive edge weights.

  • It uses a priority queue to select a node ( vertex ) nearest to the source that has not been edge relaxed.
    What is edge Relaxation in Dijkstra’s algorithm?
    Relaxing an edge in Dijkstra’s algorithm refers to updating the cost of all vertices connected to a vertex v, if those costs would be reduced by including vertex v in the path. Thus, if the source node is ( v ), then we check
    If ( distance [ adjacent-node ] > length-of-path-to-adjacent-node-from-current-source ( v ) + distance [ current-source-node ( v ) ] ) {
        distance [ adjacent-node ] = length-of-path-to-adjacent-node-from-current-source ( v ) + distance [ current-source-node ( v ) ]
    }
    Note :
    a) The distance [ ] array stores the shortest distance of every node from the source-node.
    b) Dijkstra’s algorithm begins by initializing distance [ source ] = 0 i.e the distance from source node to itself is 0 and distance [ all_other_nodes ] = ∞.

  • Since Dijkstra’s algorithm cannot handle negative edge weights, Bellman-Ford algorithm is used for finding the shortest path in a graph containing negative edge weights.

  • In a graph with only positive edge weights, Dijkstra’s algorithm with a priority queue implementation runs faster in O ((E+V) log V) than Bellman-Ford O (E.V).
    E represents the edges and V represents the vertices in the graph.


Algorithm : Dijkstra’s Shortest Path [ Java ]

1.     Initialize the distance from the source node S to all other nodes as infinite (999999999999) and to itself as 0.
2.    Insert an object of < node, distance > for source i.e < S, 0 > in a priority Queue
       where the priority of the elements in the queue is based on the length of the distance.
3.    While the Priority Queue is not empty do
4.       object_at_top = PriorityQueue. peek();
         Remove the object from the top of the Priority Queue.
         current_source_node = object_at_top . node.
5.       For every adjacent_node to current_source_node do
6.            If ( distance [ adjacent_node ] > length_of_path_to_adjacent_node_from_source + distance [ current_source_node ] ) then
7.                 distance [ adjacent_node ] = length_of_path_to_adjacent_node_from_source + distance [ current_source_node ]
8.                 Update the Priority Queue with the new object < adjacent_node, distance [ adjacent_node ] >


Below data structure is used for storing the graph before applying Dijkstra’s algorithm
Adjacency List : List of pairs of adjacent nodes and their corresponding weights in the graph.

Dijkstras_ShortestPath_DataStructure



Dijkstra’s algorithm step-by-step

This example of Dijkstra’s algorithm finds the shortest distance of all the nodes in the graph from a single / original source node 0.

Step 1 : Initialize the distance of the source node to itself as 0, and ∞ (a very large number) for the rest of the nodes.
             Insert the object < distance_from_original_source, node > in the priority queue.
             i.e Insert < 0, 0 > in the priority queue as the distance from the original source (0) to itself is 0. Dijkstras_Shortest_Path_Step_1


Step 2 : Remove the object < 0, 0 > from the front of the priority queue and relax the edge going towards every adjacent node(s) from the original source node ( 0 ).

Current
source node
Adjacent
node
Distance to the adjacent node
from the original source ( 0 )
Edge relaxation
0 1 distance [ 1 ] = ∞ distance [ 1 ] > distance_between [ 0 - 1 ] + distance [ 0 ]
i.e Since ∞ > 5 + 0
Update distance, i.e distance [ 1 ] = 5 and insert object < 1, 5 > in the priority queue.
0 2 distance [ 2 ] = ∞ distance [ 2 ] > distance_between [ 0 - 2 ] + distance [ 0 ]
i.e Since ∞ > 1 + 0
Update distance, i.e distance [ 2 ] = 1 and insert object < 2, 1 > in the priority queue.
0 3 distance [ 3 ] = ∞ distance [ 3 ] > distance_between [ 0 - 3 ] + distance [ 0 ]
i.e Since ∞ > 4 + 0
Update distance, i.e distance [ 3 ] = 4 and insert object < 3, 4 > in the priority queue.

Dijkstras_Shortest_Path_Step_2


Step 3 : Remove the object < 2, 1 > from the front of the priority queue and relax the edge going towards every adjacent node(s) from the current source ( 2 ).

Current
source node
Adjacent
node
Distance to the adjacent node
from the original source ( 0 )
Edge relaxation
2 0 distance [ 0 ] = 0 distance [ 0 ] < distance_between [ 2 - 0 ] + distance [ 2 ]
i.e Since 0 < 1 + 1
No edge relaxation needed.
2 1 distance [ 1 ] = 5 distance [ 1 ] > distance_between [ 2 - 1 ] + distance [ 2 ]
i.e Since 5 > 3 + 1
Update distance, i.e distance [ 1 ] = 4 and insert object < 1, 4 > in the priority queue.
2 3 distance [ 3 ] = 4 distance [ 3 ] > distance_between [ 2 - 3 ] + distance [ 2 ]
i.e Since 4 > 2 + 1
Update distance, i.e distance [ 3 ] = 3 and insert object < 3, 3 > in the priority queue.
2 4 distance [ 4 ] = ∞ distance [ 4 ] > distance_between [ 2 - 4 ] + distance [ 2 ]
i.e Since ∞ > 1 + 1
Update distance, i.e distance [ 4 ] = 2 and insert object < 4, 2 > in the priority queue.

Dijkstras_Shortest_Path_Step_3



Step 4 : Remove the object < 4, 2 > from the from of the priority queue and relax the edge going towards every adjacent node(s) from the current source ( 4 ).

Current
source node
Adjacent
node
Distance to the adjacent node
from the original source ( 0 )
Edge relaxation
4 1 distance [ 1 ] = 4 distance [ 1 ] < distance_between [ 4 - 1 ] + distance [ 4 ]
i.e Since 4 < 8 + 2
No edge relaxation needed.
4 2 distance [ 2 ] = 1 distance [ 2 ] < distance_between [ 4 - 2 ] + distance [ 4 ]
i.e Since 1 < 1 + 2
No edge relaxation needed.
4 3 distance [ 3 ] = 3 distance [ 3 ] < distance_between [ 4 - 3 ] + distance [ 4 ]
i.e Since 3 < 2 + 2
No edge relaxation needed.
4 5 distance [ 5 ] = ∞ distance [ 5 ] > distance_between [ 4 - 5 ] + distance [ 4 ]
i.e Since ∞ > 3 + 2
Update distance, i.e distance [ 5 ] = 5 and insert object < 5, 5 > in the priority queue.

Dijkstras_Shortest_Path_Step_4


Step 5 : Remove the object < 3, 3 > from the front of the priority queue and relax the edge going towards every adjacent node(s) from the current source ( 3 ).

Current
source node
Adjacent
node
Distance to the adjacent node
from the original source ( 0 )
Edge relaxation
3 0 distance [ 0 ] = 0 distance [ 0 ] < distance_between [ 3 - 0 ] + distance [ 3 ]
i.e Since 0 < 4 + 3
No edge relaxation needed.
3 2 distance [ 2 ] = 1 distance [ 2 ] < distance_between [ 3 - 2 ] + distance [ 3 ]
i.e Since 1 < 2 + 3
No edge relaxation needed.
3 4 distance [ 4 ] = 2 distance [ 4 ] < distance_between [ 3 - 4 ] + distance [ 3 ]
i.e Since 2 < 2 + 3
No edge relaxation needed.
3 5 distance [ 5 ] = 5 distance [ 5 ] > distance_between [ 3 - 5 ] + distance [ 3 ]
i.e Since 5 > 1 + 3
Update distance, i.e distance [ 5 ] = 4 and insert object < 5, 4 > in the priority queue.

Dijkstras_Shortest_Path_Step_5



Step 6 : Remove the object < 4, 1 > from the front of the priority queue and relax the edge going towards every adjacent node(s) from the current source ( 1 ).

Current
source node
Adjacent
node
Distance to the adjacent node
from the original source ( 0 )
Edge relaxation
1 0 distance [ 0 ] = 0 distance [ 0 ] < distance_between [ 1 - 0 ] + distance [ 1 ]
i.e Since 0 < 5 + 4
No edge relaxation needed.
1 2 distance [ 2 ] = 1 distance [ 2 ] < distance_between [ 1 - 2 ] + distance [ 1 ]
i.e Since 1 < 3 + 4
No edge relaxation needed.
1 4 distance [ 4 ] = 2 distance [ 4 ] < distance_between [ 1 - 4 ] + distance [ 1 ]
i.e Since 2 < 8 + 4
No edge relaxation needed.

Dijkstras_Shortest_Path_Step_6


Step 7 : Remove the object < 4, 5 > from the front of the priority queue and relax the edge going towards every adjacent node(s) from the current source ( 5 ).

Current
source node
Adjacent
node
Distance to the adjacent node
from the original source ( 0 )
Edge relaxation
5 3 distance [ 3 ] = 3 distance [ 3 ] < distance_between [ 5 - 3 ] + distance [ 5 ]
i.e Since 3 < 1 + 4
No edge relaxation needed.
5 4 distance [ 4 ] = 2 distance [ 4 ] < distance_between [ 5 - 4 ] + distance [ 5 ]
i.e Since 2 < 3 + 4
No edge relaxation needed.

The algorithm terminates here as the priority queue is empty and we have calculated the shortest path to all the nodes from the original source 0 as shown below.

Dijkstras_Shortest_Path_Step_7


Data structure used for running Dijkstra’s shortest path : Distance based priority queue for choosing the vertex nearest to the source.
Graph type: Designed for weighted (directed / un-directed) graph containing positive edge weights.
Time complexity of Dijkstra’s algorithm : O ( (E+V) Log(V) ) for an adjacency list implementation of a graph. V is the number of vertices and E is the number of edges in a graph.



import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import java.util.PriorityQueue;
import java.util.Comparator;

class NodeDist {

    int node; // Adjacent node
    long dist; // Distance to adjacent node

    NodeDist (int node, long dist) {
        this.node = node;
        this.dist = dist;
    }
}

class Dijkstras {

    void ShortestPath (int source_node, int node_count, List<List<NodeDist>> graph) {

        // Assume that the distance from the source_node to other nodes is infinite 
        // in the beginnging, i.e initialize the distance list to a max value
        Long INF = (long) 999999999;
        List<Long> dist = new ArrayList<Long>(Collections.nCopies(node_count, INF));

        // Distance from the source vertex to itself is 0
        dist.set(source_node, (long) 0); // (Node, Dist)

        // Comparator lambda function that enables the priority queue to store the nodes
        // based on the distance in the ascending order.
        Comparator<NodeDist> NodeDistComparator = (obj1, obj2) -> {
            if (obj1.dist < obj2.dist)
                return 1;
            if (obj1.dist > obj2.dist)
                return -1; 
            return 0;
        };

        // Priority queue stores the object node-distance into the queue with 
        // the smallest distance node at the top.
        PriorityQueue<NodeDist> pq = new PriorityQueue<>(NodeDistComparator);

        pq.add(new NodeDist(source_node, 0));

        while (!pq.isEmpty()) {

            NodeDist obj = pq.peek();
            pq.remove();

            int current_source = obj.node;

            for (NodeDist obj_node_dist : graph.get(current_source)) {

                int adj_node = obj_node_dist.node;
                long length_to_adjnode = obj_node_dist.dist;

                // Edge relaxation 
                if (dist.get(adj_node) > length_to_adjnode + dist.get(current_source)) {

                    // If the distance to the adjacent node is not INF, means the object <node, dist> is in the priority queue.
                    // Remove the object before updating it in the priority queue.
                    if (dist.get(adj_node) != INF) {
                        pq.remove(new NodeDist(adj_node, dist.get(adj_node)));
                    }
                    dist.set(adj_node, length_to_adjnode + dist.get(current_source));
                    pq.add(new NodeDist(adj_node, dist.get(adj_node)));
                }
            }
        }

        for (int i=0; i<node_count; i++)
            System.out.println("Source Node(" + source_node + ") -> Destination Node(" + i + ") : " + dist.get(i));
    }

    public static void main(String args[]) {

        int node_count = 6;
        List<List<NodeDist>> graph = new ArrayList<>(node_count);

        for(int i=0; i<node_count; i++) {
            graph.add(new ArrayList<>());
        }

        // Node 0: <1,5> <2,1> <3,4>
        Collections.addAll(graph.get(0), new NodeDist(1, 5), new NodeDist(2, 1), new NodeDist(3, 4));

        // Node 1: <0,5> <2,3> <4,8>
        Collections.addAll(graph.get(1), new NodeDist(0, 5), new NodeDist(2, 3), new NodeDist(4, 8));

        // Node 2: <0,1> <1,3> <3,2> <4,1>
        Collections.addAll(graph.get(2), new NodeDist(0, 1), new NodeDist(1, 3), new NodeDist(3, 2), new NodeDist(4, 1));

        // Node 3: <0,4> <2,2> <4,2> <5,1>
        Collections.addAll(graph.get(3), new NodeDist(0, 4), new NodeDist(2, 2), new NodeDist(4, 2), new NodeDist(5, 1));

        // Node 4: <1,8> <2,1> <3,2> <5,3>
        Collections.addAll(graph.get(4), new NodeDist(1, 8), new NodeDist(2, 1), new NodeDist(3, 2), new NodeDist(5, 3));

        // Node 5: <3,1> <4,3> 
        Collections.addAll(graph.get(5), new NodeDist(3, 1), new NodeDist(4, 3));

        int source_node = 0;
        Dijkstras d = new Dijkstras();
        d.ShortestPath(source_node, node_count, graph);

        System.out.println();
        source_node = 5;
        d.ShortestPath(source_node, node_count, graph);
    }   
}

Output

Source Node(0) -> Destination Node(0) : 0
Source Node(0) -> Destination Node(1) : 4
Source Node(0) -> Destination Node(2) : 1
Source Node(0) -> Destination Node(3) : 3
Source Node(0) -> Destination Node(4) : 2
Source Node(0) -> Destination Node(5) : 4

Source Node(5) -> Destination Node(0) : 4
Source Node(5) -> Destination Node(1) : 6
Source Node(5) -> Destination Node(2) : 3
Source Node(5) -> Destination Node(3) : 1
Source Node(5) -> Destination Node(4) : 3
Source Node(5) -> Destination Node(5) : 0


Copyright (c) 2019-2024, Algotree.org.
All rights reserved.