Monday, September 23, 2024
Google search engine
HomeData Modelling & AIShortest path in an unweighted graph

Shortest path in an unweighted graph

Given an unweighted graph, a source, and a destination, we need to find the shortest path from source to destination in the graph in the most optimal way.

unweighted graph

unweighted graph of 8 vertices 

Input: source vertex = 0 and destination vertex is = 7.
Output: Shortest path length is:2
Path is::
0 3 7
Input: source vertex is = 2 and destination vertex is = 6.
Output: Shortest path length is:5
Path is::
2 1 0 3 4 6

One solution is to solve in O(VE) time using Bellman–Ford. If there are no negative weight cycles, then we can solve in O(E + VLogV) time using Dijkstra’s algorithm
Since the graph is unweighted, we can solve this problem in O(V + E) time. The idea is to use a modified version of Breadth-first search in which we keep storing the predecessor of a given vertex while doing the breadth-first search. 

We first initialize an array dist[0, 1, …., v-1] such that dist[i] stores the distance of vertex i from the source vertex and array pred[0, 1, ….., v-1] such that pred[i] represents the immediate predecessor of the vertex i in the breadth-first search starting from the source. 

Now we get the length of the path from source to any other vertex in O(1) time from array d, and for printing the path from source to any vertex we can use array p and that will take O(V) time in worst case as V is the size of array P. So most of the time of the algorithm is spent in doing the Breadth-first search from a given source which we know takes O(V+E) time. Thus the time complexity of our algorithm is O(V+E). 

Take the following unweighted graph as an example:

Following is the complete algorithm for finding the shortest path: 

Implementation:

C++




// CPP code for printing shortest path between
// two vertices of unweighted graph
#include <bits/stdc++.h>
using namespace std;
 
// utility function to form edge between two vertices
// source and dest
void add_edge(vector<int> adj[], int src, int dest)
{
    adj[src].push_back(dest);
    adj[dest].push_back(src);
}
 
// a modified version of BFS that stores predecessor
// of each vertex in array p
// and its distance from source in array d
bool BFS(vector<int> adj[], int src, int dest, int v,
         int pred[], int dist[])
{
    // a queue to maintain queue of vertices whose
    // adjacency list is to be scanned as per normal
    // DFS algorithm
    list<int> queue;
 
    // boolean array visited[] which stores the
    // information whether ith vertex is reached
    // at least once in the Breadth first search
    bool visited[v];
 
    // initially all vertices are unvisited
    // so v[i] for all i is false
    // and as no path is yet constructed
    // dist[i] for all i set to infinity
    for (int i = 0; i < v; i++) {
        visited[i] = false;
        dist[i] = INT_MAX;
        pred[i] = -1;
    }
 
    // now source is first to be visited and
    // distance from source to itself should be 0
    visited[src] = true;
    dist[src] = 0;
    queue.push_back(src);
 
    // standard BFS algorithm
    while (!queue.empty()) {
        int u = queue.front();
        queue.pop_front();
        for (int i = 0; i < adj[u].size(); i++) {
            if (visited[adj[u][i]] == false) {
                visited[adj[u][i]] = true;
                dist[adj[u][i]] = dist[u] + 1;
                pred[adj[u][i]] = u;
                queue.push_back(adj[u][i]);
 
                // We stop BFS when we find
                // destination.
                if (adj[u][i] == dest)
                    return true;
            }
        }
    }
 
    return false;
}
 
// utility function to print the shortest distance
// between source vertex and destination vertex
void printShortestDistance(vector<int> adj[], int s,
                           int dest, int v)
{
    // predecessor[i] array stores predecessor of
    // i and distance array stores distance of i
    // from s
    int pred[v], dist[v];
 
    if (BFS(adj, s, dest, v, pred, dist) == false) {
        cout << "Given source and destination"
             << " are not connected";
        return;
    }
 
    // vector path stores the shortest path
    vector<int> path;
    int crawl = dest;
    path.push_back(crawl);
    while (pred[crawl] != -1) {
        path.push_back(pred[crawl]);
        crawl = pred[crawl];
    }
 
    // distance from source is in distance array
    cout << "Shortest path length is : "
         << dist[dest];
 
    // printing path from source to destination
    cout << "\nPath is::\n";
    for (int i = path.size() - 1; i >= 0; i--)
        cout << path[i] << " ";
}
 
// Driver program to test above functions
int main()
{
    // no. of vertices
    int v = 8;
 
    // array of vectors is used to store the graph
    // in the form of an adjacency list
    vector<int> adj[v];
 
    // Creating graph given in the above diagram.
    // add_edge function takes adjacency list, source
    // and destination vertex as argument and forms
    // an edge between them.
    add_edge(adj, 0, 1);
    add_edge(adj, 0, 3);
    add_edge(adj, 1, 2);
    add_edge(adj, 3, 4);
    add_edge(adj, 3, 7);
    add_edge(adj, 4, 5);
    add_edge(adj, 4, 6);
    add_edge(adj, 4, 7);
    add_edge(adj, 5, 6);
    add_edge(adj, 6, 7);
    int source = 0, dest = 7;
    printShortestDistance(adj, source, dest, v);
    return 0;
}


Java




// Java program to find shortest path in an undirected
// graph
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
 
public class pathUnweighted {
 
    // Driver Program
    public static void main(String args[])
    {
        // No of vertices
        int v = 8;
 
        // Adjacency list for storing which vertices are connected
        ArrayList<ArrayList<Integer>> adj =
                            new ArrayList<ArrayList<Integer>>(v);
        for (int i = 0; i < v; i++) {
            adj.add(new ArrayList<Integer>());
        }
 
        // Creating graph given in the above diagram.
        // add_edge function takes adjacency list, source
        // and destination vertex as argument and forms
        // an edge between them.
        addEdge(adj, 0, 1);
        addEdge(adj, 0, 3);
        addEdge(adj, 1, 2);
        addEdge(adj, 3, 4);
        addEdge(adj, 3, 7);
        addEdge(adj, 4, 5);
        addEdge(adj, 4, 6);
        addEdge(adj, 4, 7);
        addEdge(adj, 5, 6);
        addEdge(adj, 6, 7);
        int source = 0, dest = 7;
        printShortestDistance(adj, source, dest, v);
    }
 
    // function to form edge between two vertices
    // source and dest
    private static void addEdge(ArrayList<ArrayList<Integer>> adj, int i, int j)
    {
        adj.get(i).add(j);
        adj.get(j).add(i);
    }
 
    // function to print the shortest distance and path
    // between source vertex and destination vertex
    private static void printShortestDistance(
                     ArrayList<ArrayList<Integer>> adj,
                             int s, int dest, int v)
    {
        // predecessor[i] array stores predecessor of
        // i and distance array stores distance of i
        // from s
        int pred[] = new int[v];
        int dist[] = new int[v];
 
        if (BFS(adj, s, dest, v, pred, dist) == false) {
            System.out.println("Given source and destination" +
                                         "are not connected");
            return;
        }
 
        // LinkedList to store path
        LinkedList<Integer> path = new LinkedList<Integer>();
        int crawl = dest;
        path.add(crawl);
        while (pred[crawl] != -1) {
            path.add(pred[crawl]);
            crawl = pred[crawl];
        }
 
        // Print distance
        System.out.println("Shortest path length is: " + dist[dest]);
 
        // Print path
        System.out.println("Path is ::");
        for (int i = path.size() - 1; i >= 0; i--) {
            System.out.print(path.get(i) + " ");
        }
    }
 
    // a modified version of BFS that stores predecessor
    // of each vertex in array pred
    // and its distance from source in array dist
    private static boolean BFS(ArrayList<ArrayList<Integer>> adj, int src,
                                  int dest, int v, int pred[], int dist[])
    {
        // a queue to maintain queue of vertices whose
        // adjacency list is to be scanned as per normal
        // BFS algorithm using LinkedList of Integer type
        LinkedList<Integer> queue = new LinkedList<Integer>();
 
        // boolean array visited[] which stores the
        // information whether ith vertex is reached
        // at least once in the Breadth first search
        boolean visited[] = new boolean[v];
 
        // initially all vertices are unvisited
        // so v[i] for all i is false
        // and as no path is yet constructed
        // dist[i] for all i set to infinity
        for (int i = 0; i < v; i++) {
            visited[i] = false;
            dist[i] = Integer.MAX_VALUE;
            pred[i] = -1;
        }
 
        // now source is first to be visited and
        // distance from source to itself should be 0
        visited[src] = true;
        dist[src] = 0;
        queue.add(src);
 
        // bfs Algorithm
        while (!queue.isEmpty()) {
            int u = queue.remove();
            for (int i = 0; i < adj.get(u).size(); i++) {
                if (visited[adj.get(u).get(i)] == false) {
                    visited[adj.get(u).get(i)] = true;
                    dist[adj.get(u).get(i)] = dist[u] + 1;
                    pred[adj.get(u).get(i)] = u;
                    queue.add(adj.get(u).get(i));
 
                    // stopping condition (when we find
                    // our destination)
                    if (adj.get(u).get(i) == dest)
                        return true;
                }
            }
        }
        return false;
    }
}
// This code is contributed by Sahil Vaid


Python3




# Python3 code for printing shortest path between
# two vertices of unweighted graph
  
# utility function to form edge between two vertices
# source and dest
def add_edge(adj, src, dest):
 
    adj[src].append(dest);
    adj[dest].append(src);
  
# a modified version of BFS that stores predecessor
# of each vertex in array p
# and its distance from source in array d
def BFS(adj, src, dest, v, pred, dist):
 
    # a queue to maintain queue of vertices whose
    # adjacency list is to be scanned as per normal
    # DFS algorithm
    queue = []
  
    # boolean array visited[] which stores the
    # information whether ith vertex is reached
    # at least once in the Breadth first search
    visited = [False for i in range(v)];
  
    # initially all vertices are unvisited
    # so v[i] for all i is false
    # and as no path is yet constructed
    # dist[i] for all i set to infinity
    for i in range(v):
 
        dist[i] = 1000000
        pred[i] = -1;
     
    # now source is first to be visited and
    # distance from source to itself should be 0
    visited[src] = True;
    dist[src] = 0;
    queue.append(src);
  
    # standard BFS algorithm
    while (len(queue) != 0):
        u = queue[0];
        queue.pop(0);
        for i in range(len(adj[u])):
         
            if (visited[adj[u][i]] == False):
                visited[adj[u][i]] = True;
                dist[adj[u][i]] = dist[u] + 1;
                pred[adj[u][i]] = u;
                queue.append(adj[u][i]);
  
                # We stop BFS when we find
                # destination.
                if (adj[u][i] == dest):
                    return True;
  
    return False;
  
# utility function to print the shortest distance
# between source vertex and destination vertex
def printShortestDistance(adj, s, dest, v):
     
    # predecessor[i] array stores predecessor of
    # i and distance array stores distance of i
    # from s
    pred=[0 for i in range(v)]
    dist=[0 for i in range(v)];
  
    if (BFS(adj, s, dest, v, pred, dist) == False):
        print("Given source and destination are not connected")
  
    # vector path stores the shortest path
    path = []
    crawl = dest;
    path.append(crawl);
     
    while (pred[crawl] != -1):
        path.append(pred[crawl]);
        crawl = pred[crawl];
     
  
    # distance from source is in distance array
    print("Shortest path length is : " + str(dist[dest]), end = '')
  
    # printing path from source to destination
    print("\nPath is : : ")
     
    for i in range(len(path)-1, -1, -1):
        print(path[i], end=' ')
         
# Driver program to test above functions
if __name__=='__main__':
     
    # no. of vertices
    v = 8;
  
    # array of vectors is used to store the graph
    # in the form of an adjacency list
    adj = [[] for i in range(v)];
  
    # Creating graph given in the above diagram.
    # add_edge function takes adjacency list, source
    # and destination vertex as argument and forms
    # an edge between them.
    add_edge(adj, 0, 1);
    add_edge(adj, 0, 3);
    add_edge(adj, 1, 2);
    add_edge(adj, 3, 4);
    add_edge(adj, 3, 7);
    add_edge(adj, 4, 5);
    add_edge(adj, 4, 6);
    add_edge(adj, 4, 7);
    add_edge(adj, 5, 6);
    add_edge(adj, 6, 7);
    source = 0
    dest = 7;
    printShortestDistance(adj, source, dest, v);
 
    # This code is contributed by rutvik_56


C#




// C# program to find shortest
// path in an undirected graph
using System;
using System.Collections.Generic;
class pathUnweighted{
 
// Driver code
public static void Main(String []args)
{
  // No of vertices
  int v = 8;
 
  // Adjacency list for storing
  // which vertices are connected
  List<List<int>> adj =
            new List<List<int>>(v);
   
  for (int i = 0; i < v; i++)
  {
    adj.Add(new List<int>());
  }
 
  // Creating graph given in the
  // above diagram. add_edge
  // function takes adjacency list,
  // source and destination vertex
  // as argument and forms an edge
  // between them.
  addEdge(adj, 0, 1);
  addEdge(adj, 0, 3);
  addEdge(adj, 1, 2);
  addEdge(adj, 3, 4);
  addEdge(adj, 3, 7);
  addEdge(adj, 4, 5);
  addEdge(adj, 4, 6);
  addEdge(adj, 4, 7);
  addEdge(adj, 5, 6);
  addEdge(adj, 6, 7);
  int source = 0, dest = 7;
  printShortestDistance(adj, source,
                        dest, v);
}
 
// function to form edge between
// two vertices source and dest
private static void addEdge(List<List<int>> adj,
                            int i, int j)
{
  adj[i].Add(j);
  adj[j].Add(i);
}
 
// function to print the shortest
// distance and path between source
// vertex and destination vertex
private static void printShortestDistance(List<List<int>> adj,
                                          int s, int dest, int v)
{
  // predecessor[i] array stores
  // predecessor of i and distance
  // array stores distance of i
  // from s
  int []pred = new int[v];
  int []dist = new int[v];
 
  if (BFS(adj, s, dest,
          v, pred, dist) == false)
  {
    Console.WriteLine("Given source and destination" +
                      "are not connected");
    return;
  }
 
  // List to store path
  List<int> path = new List<int>();
  int crawl = dest;
  path.Add(crawl);
   
  while (pred[crawl] != -1)
  {
    path.Add(pred[crawl]);
    crawl = pred[crawl];
  }
 
  // Print distance
  Console.WriteLine("Shortest path length is: " +
                     dist[dest]);
 
  // Print path
  Console.WriteLine("Path is ::");
   
  for (int i = path.Count - 1;
           i >= 0; i--)
  {
    Console.Write(path[i] + " ");
  }
}
 
// a modified version of BFS that
// stores predecessor of each vertex
// in array pred and its distance
// from source in array dist
private static bool BFS(List<List<int>> adj,
                        int src, int dest,
                        int v, int []pred,
                        int []dist)
{
  // a queue to maintain queue of
  // vertices whose adjacency list
  // is to be scanned as per normal
  // BFS algorithm using List of int type
  List<int> queue = new List<int>();
 
  // bool array visited[] which
  // stores the information whether
  // ith vertex is reached at least
  // once in the Breadth first search
  bool []visited = new bool[v];
 
  // initially all vertices are
  // unvisited so v[i] for all i
  // is false and as no path is
  // yet constructed dist[i] for
  // all i set to infinity
  for (int i = 0; i < v; i++)
  {
    visited[i] = false;
    dist[i] = int.MaxValue;
    pred[i] = -1;
  }
 
  // now source is first to be
  // visited and distance from
  // source to itself should be 0
  visited[src] = true;
  dist[src] = 0;
  queue.Add(src);
 
  // bfs Algorithm
  while (queue.Count != 0)
  {
    int u = queue[0];
    queue.RemoveAt(0);
     
    for (int i = 0;
             i < adj[u].Count; i++)
    {
      if (visited[adj[u][i]] == false)
      {
        visited[adj[u][i]] = true;
        dist[adj[u][i]] = dist[u] + 1;
        pred[adj[u][i]] = u;
        queue.Add(adj[u][i]);
 
        // stopping condition (when we
        // find our destination)
        if (adj[u][i] == dest)
          return true;
      }
    }
  }
  return false;
}
}
 
// This code is contributed by Rajput-Ji


Javascript




// JavaScript code for printing shortest path between
// two vertices of unweighted graph
const max_value = 9007199254740992;
 
// utility function to form edge between two vertices
// source and dest
function add_edge(adj, src, dest){
    adj[src].push(dest);
    adj[dest].push(src);
}
 
// a modified version of BFS that stores predecessor
// of each vertex in array p
// and its distance from source in array d
function BFS(adj, src, dest, v, pred, dist)
{
    // a queue to maintain queue of vertices whose
    // adjacency list is to be scanned as per normal
    // DFS algorithm
    let queue = [];
 
    // boolean array visited[] which stores the
    // information whether ith vertex is reached
    // at least once in the Breadth first search
    let visited = new Array(v);
 
    // initially all vertices are unvisited
    // so v[i] for all i is false
    // and as no path is yet constructed
    // dist[i] for all i set to infinity
    for (let i = 0; i < v; i++) {
        visited[i] = false;
        dist[i] = max_value;
        pred[i] = -1;
    }
 
    // now source is first to be visited and
    // distance from source to itself should be 0
    visited[src] = true;
    dist[src] = 0;
    queue.push(src);
 
    // standard BFS algorithm
    while (queue.length > 0) {
        let u = queue[0];
        queue.shift();
        for (let i = 0; i < adj[u].length; i++) {
            if (visited[adj[u][i]] == false) {
                visited[adj[u][i]] = true;
                dist[adj[u][i]] = dist[u] + 1;
                pred[adj[u][i]] = u;
                queue.push(adj[u][i]);
 
                // We stop BFS when we find
                // destination.
                if (adj[u][i] == dest)
                    return true;
            }
        }
    }
 
    return false;
}
 
// utility function to print the shortest distance
// between source vertex and destination vertex
function printShortestDistance(adj, s, dest, v)
{
    // predecessor[i] array stores predecessor of
    // i and distance array stores distance of i
    // from s
    let pred = new Array(v).fill(0);
    let dist = new Array(v).fill(0);
 
    if (BFS(adj, s, dest, v, pred, dist) == false) {
        console.log("Given source and destination are not connected");
    }
 
    // vector path stores the shortest path
    let path = new Array();
    let crawl = dest;
    path.push(crawl);
    while (pred[crawl] != -1) {
        path.push(pred[crawl]);
        crawl = pred[crawl];
    }
 
    // distance from source is in distance array
    console.log("Shortest path length is : ", dist[dest]);
 
 
    // printing path from source to destination
    console.log("Path is::");
 
    for (let i = path.length - 1; i >= 0; i--)
        console.log(path[i]);
}
 
// Driver program to test above functions
// no. of vertices
let v = 8;
 
// array of vectors is used to store the graph
// in the form of an adjacency list
let adj = new Array(v).fill(0);
 
for(let i = 0; i < v; i++){
    adj[i] = new Array();
}
 
// Creating graph given in the above diagram.
// add_edge function takes adjacency list, source
// and destination vertex as argument and forms
// an edge between them.
add_edge(adj, 0, 1);
add_edge(adj, 0, 3);
add_edge(adj, 1, 2);
add_edge(adj, 3, 4);
add_edge(adj, 3, 7);
add_edge(adj, 4, 5);
add_edge(adj, 4, 6);
add_edge(adj, 4, 7);
add_edge(adj, 5, 6);
add_edge(adj, 6, 7);
let source = 0;
let dest = 7;
printShortestDistance(adj, source, dest, v);
 
// The code is contributed by Gautam goel


Output

Shortest path length is : 2
Path is::
0 3 7 

Time Complexity : O(V + E) 
Auxiliary Space: O(V)

Algorithm

Create a queue and add the starting vertex to it.
Create an array to keep track of the distances from the starting vertex to all other vertices. Initialize all distances to infinity except for the starting vertex, which should have a distance of 0.
While the queue is not empty, dequeue the next vertex.
For each neighbor of the dequeued vertex that has not been visited, set its distance to the distance of the dequeued vertex plus 1 and add it to the queue.
Repeat steps 3-4 until the queue is empty.
The distances array now contains the shortest path distances from the starting vertex to all other vertices.

Program

Python3




from collections import deque
 
def bfs_shortest_path(graph, start):
    # Create a queue and add the starting vertex to it
    queue = deque([start])
     
    # Create an array to keep track of the distances from the starting vertex to all other vertices
    distances = [float('inf')] * len(graph)
    distances[start] = 0
     
    # Create a set to keep track of visited vertices
    visited = set()
     
    # Perform BFS
    while queue:
        # Dequeue the next vertex
        vertex = queue.popleft()
        visited.add(vertex)
         
        # Update the distances of neighbors
        for neighbor in graph[vertex]:
            if neighbor not in visited:
                distances[neighbor] = distances[vertex] + 1
                queue.append(neighbor)
     
    return distances
 
 
# Example graph: unweighted, directed graph with 5 vertices
# Vertices are represented by integers 0 through 4
# Edges: (0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (3, 4)
 
graph = [[1, 2], [2, 3], [3], [4], []]
 
start_vertex = 0
distances = bfs_shortest_path(graph, start_vertex)
 
print(distances)  # Output: [0, 1, 1, 2, 3]


C#




using System;
using System.Collections.Generic;
 
public class GFG
{
    public static int[] BfsShortestPath(List<List<int>> graph, int start)
    {
        Queue<int> queue = new Queue<int>();
        queue.Enqueue(start);
 
        // Create an array to keep track of the distances from the starting vertex to all other vertices
        int[] distances = new int[graph.Count];
        for (int i = 0; i < distances.Length; i++)
        {
            distances[i] = int.MaxValue; // Initialize all distances to infinity
        }
        distances[start] = 0; // Distance to the starting vertex is 0
 
        HashSet<int> visited = new HashSet<int>(); // Create a set to keep track of visited vertices
 
        while (queue.Count > 0)
        {
            int vertex = queue.Dequeue(); // Dequeue the next vertex
            visited.Add(vertex); // Mark the vertex as visited
 
            // Update the distances of neighbors
            foreach (int neighbor in graph[vertex])
            {
                if (!visited.Contains(neighbor))
                {
                    distances[neighbor] = distances[vertex] + 1; // Update distance to neighbor
                    queue.Enqueue(neighbor); // Enqueue the unvisited neighbor
                }
            }
        }
 
        return distances; // Return the array of shortest distances
    }
 
    public static void Main()
    {
        // Example graph: unweighted, directed graph with 5 vertices
        // Vertices are represented by integers 0 through 4
        // Edges: (0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (3, 4)
        List<List<int>> graph = new List<List<int>>()
        {
            new List<int> {1, 2},
            new List<int> {2, 3},
            new List<int> {3},
            new List<int> {4},
            new List<int>()
        };
 
        int startVertex = 0;
        int[] distances = BfsShortestPath(graph, startVertex);
 
        // Output: [0, 1, 1, 2, 3]
        foreach (int distance in distances)
        {
            Console.Write(distance + " ");
        }
 
        Console.WriteLine();
    }
}


Output

[0, 1, 2, 3, 4]

In the above example, the output [0, 1, 1, 2, 3] indicates that the shortest path from vertex 0 to vertex 1 is of length 1, the shortest path from vertex 0 to vertex 2 is also of length 1, and so on.

Time and Auxiliary space

The time complexity of the above BFS-based algorithm for finding the shortest path in an unweighted graph is O(V + E), where V is the number of vertices and E is the number of edges in the graph. This is because each vertex and edge is visited at most once during the BFS traversal.

The space complexity of the algorithm is also O(V + E), due to the use of the distances array to store the shortest distances from the starting vertex to all other vertices, and the visited set to keep track of visited vertices. The queue used for BFS traversal can also have a maximum size of O(V + E) in the worst case, which contributes to the space complexity.

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

RELATED ARTICLES

Most Popular

Recent Comments