Skip to content

Latest commit

 

History

History

README.md

Project 2: The Dijkstra’s Algorithm

Dijkstra’s Algorithm Java

Abstract:

This project addresses how the choice of the input graph representation and the priority queue implementation will affect the time complexity of Dijkstra’s Algorithm. This repository, contains the following files,

  1. DijkstraA.java, graph G is represented using an Adjacency Matrix with an Array-based Priority Queue.

  2. DijkstraB.java, graph G is represented using an Adjacency List with a Min-Heap Priority Queue

  3. generateInput.java, generation of input graph G

1. Sparse vs. Dense Graphs: Characteristics and Generation

In the generation of input graphs G = (V, E) where (V) ranges from 3 to 1000, we make the following assumptions and considerations:

Graph Type Connected Complete Edges
Sparse Graph Yes No (V - 1)
Dense Graph Yes Yes V(V – 1)/2

Assumptions:

  1. Sparse Graph:

    • Connected: Yes, ensuring all vertices are reachable.
    • Complete: No, allowing for fewer edges than the maximum possible.
    • Edges: (V - 1), the minimum number of edges in the graph.
  2. Dense Graph:

    • Connected: Yes, ensuring all vertices are reachable.
    • Complete: Yes, with edges reaching the maximum possible.
    • Edges: V(V – 1)/2, forming a fully connected graph.

By defining these characteristics, we aim to explore the behaviour and performance of algorithms on graphs with varying densities.
Once the graph is generated, it is saved in a .txt file. The .txt file would be read and converted to a adjacency matrix or adjacency list representation in the respective DijkstraA.java and DijkstraB.java files.

To find more details on our graph generation, click here.

2. Implementation of Dijkstra’s Algorithm.

The pseudocode for Dijkstra’s Algorithm is as follows.

// graph: input (sparse/dense) graph, 
// source: Source vertex

Dijkstra(graph, source):
    n = number of vertices in graph
    d = array of distances initialized to INF
    pi = array of predecessors initialized to -1
    S = array of visited vertices initialized to 0

    d[source] = 0
    priorityQueue = createPriorityQueue()

    for i = 0 to n-1:
        enqueue(priorityQueue, (d[i], i))

    while priorityQueue is not empty:
        (minDistance, u) = dequeueMin(priorityQueue)
        S[u] = 1

        for each neighbor v of u:
            if S[v] == 0 and d[u] + weight(u, v) < d[v]:
                decreaseKey(priorityQueue, v, d[u] + weight(u, v))
                d[v] = d[u] + weight(u, v)
                pi[v] = u

To find more details of how the Priority Queue is implemented in the respective file, click DijkstraA.java and DijkstraB.java.

2. Graph G - Represented using an Adjacency Matrix with an Array-based Priority Queue

Respective Sparse & Dense Graph with DijkstraA Algorithm: image

Comparing Sparse Vs. Dense Graph with DijkstraA Algorithm: image

3. Graph G - Represented as an Adjacency List with a Min-Heap for the Priority Queue

Respective Sparse & Dense Graph with DijkstraB Algorithm: image

Comparing Sparse Vs. Dense Graph with DijkstraB Algorithm: image

4. Comparison between Implementations (2) and (3)

Sparse Graph: image

Dense Graph: image

Conclusion

From our empirical analysis, DijkstraB performs better on a sparse graph, while DijkstraA performs better on a dense graph.