Topological Sorting in Graph Data Structure



Topological sorting is a way of arranging the nodes of a Directed Acyclic Graph (DAG) in a line, making sure that for every directed edge from u to v, node u comes before v. If the graph has cycles, topological sorting isn't possible.

In topological sorting, if theres an edge from u to v, u should come before v in the order. Its different from DFS, where we visit a node and then explore its neighbors. In topological sorting, a node should be printed before any of its connected nodes.

Now, lets understand Directed Acyclic Graphs (DAGs). A directed graph has edges that go from one node to another in a specific direction. It is called acyclic if there are no cyclesmeaning theres no way to start from a node and return to it by following edges.

Topological sorting only works for DAGs. If theres a cycle in the graph, we cant arrange the nodes in a proper order because some nodes will keep pointing back, making a valid linear order impossible.

Topological Sort

Topological Sort Algorithm

Topological sorting can be done using Depth First Search (DFS) algorithm. The algorithm follows the following steps:

Algorithm

Following are the steps to perform topological sorting using DFS:

  • Call the DFS function for a vertex u.
  • In the DFS function, mark the vertex u as visited.
  • For every adjacent vertex v of u, if v is not visited, then call the DFS function for vertex v.
  • After visiting all the adjacent vertices of vertex u, add the vertex u to the topological order list.

After performing the above steps for all the vertices, the topological order list will have the vertices in topological order.

Code for Topological Sort

Let's see the code for topological sorting using Depth First Search (DFS) algorithm:

#include <stdio.h>

#define MAX_VERTICES 6

int adj[MAX_VERTICES][MAX_VERTICES] = {
   {0, 1, 1, 0, 0, 0},
   {0, 0, 0, 1, 1, 0},
   {0, 0, 0, 0, 1, 0},
   {0, 0, 0, 0, 0, 1},
   {0, 0, 0, 0, 0, 1},
   {0, 0, 0, 0, 0, 0}
};

int visited[MAX_VERTICES] = {0};
int topological_order[MAX_VERTICES];
int order_index = MAX_VERTICES - 1;

void DFS(int vertex) {
   visited[vertex] = 1;
   for (int v = 0; v < MAX_VERTICES; v++) {
      if (adj[vertex][v] && !visited[v]) {
         DFS(v);
      }
   }
   topological_order[order_index--] = vertex;
}

void topological_sort() {
   for (int v = 0; v < MAX_VERTICES; v++) {
      if (!visited[v]) {
         DFS(v);
      }
   }
}

void print_topological_order() {
   printf("Topological Order: ");
   for (int i = 0; i < MAX_VERTICES; i++) {
      printf("%d ", topological_order[i]);
   }
   printf("\n");
}

int main() {
   topological_sort();
   print_topological_order();
   return 0;
}

Output

Following is the output of the above code:

Topological Order: 0 2 1 3 4 5
#include <iostream>
#include <vector>
using namespace std;

#define MAX_VERTICES 6
int adj[MAX_VERTICES][MAX_VERTICES] = {
   {0, 1, 1, 0, 0, 0},
   {0, 0, 0, 1, 1, 0},
   {0, 0, 0, 0, 1, 0},
   {0, 0, 0, 0, 0, 1},
   {0, 0, 0, 0, 0, 1},
   {0, 0, 0, 0, 0, 0}
};

int visited[MAX_VERTICES] = {0};
vector<int> topological_order;

void DFS(int vertex) {
   visited[vertex] = 1;
   for (int v = 0; v < MAX_VERTICES; v++) {
      if (adj[vertex][v] && !visited[v]) {
         DFS(v);
      }
   }
   topological_order.push_back(vertex);
}

void topological_sort() {
   for (int v = 0; v < MAX_VERTICES; v++) {
      if (!visited[v]) {
         DFS(v);
      }
   }
}

void print_topological_order() {
   cout << "Topological Order: ";
   for (int i = topological_order.size() - 1; i >= 0; i--) {
      cout << topological_order[i] << " ";
   }
   cout << endl;
}

int main() {
   topological_sort();
   print_topological_order();
   return 0;
}

Output

Topological Order: 0 2 1 3 4 5
// Java program to implement topological sort using DFS
import java.util.*;

public class Main {
   static final int MAX_VERTICES = 6;
   static int[][] adj = {
      {0, 1, 1, 0, 0, 0},
      {0, 0, 0, 1, 1, 0},
      {0, 0, 0, 0, 1, 0},
      {0, 0, 0, 0, 0, 1},
      {0, 0, 0, 0, 0, 1},
      {0, 0, 0, 0, 0, 0}
   };
   static int[] visited = new int[MAX_VERTICES];
   static List<Integer> topological_order = new ArrayList<>();

   static void DFS(int vertex) {
      visited[vertex] = 1;
      for (int v = 0; v < MAX_VERTICES; v++) {
         if (adj[vertex][v] == 1 && visited[v] == 0) {
            DFS(v);
         }
      }
      topological_order.add(vertex);
   }

   static void topological_sort() {
      for (int v = 0; v < MAX_VERTICES; v++) {
         if (visited[v] == 0) {
            DFS(v);
         }
      }
   }

   static void print_topological_order() {
      System.out.print("Topological Order: ");
      for (int i = topological_order.size() - 1; i >= 0; i--) {
         System.out.print(topological_order.get(i) + " ");
      }
      System.out.println();
   }

   public static void main(String[] args) {
      topological_sort();
      print_topological_order();
   }
}

Output

Topological Order: 0 2 1 3 4 5
# Python program to implement topological sort using DFS
MAX_VERTICES = 6
adj = [
   [0, 1, 1, 0, 0, 0],
   [0, 0, 0, 1, 1, 0],
   [0, 0, 0, 0, 1, 0],
   [0, 0, 0, 0, 0, 1],
   [0, 0, 0, 0, 0, 1],
   [0, 0, 0, 0, 0, 0]
]

visited = [0] * MAX_VERTICES
topological_order = []

def DFS(vertex):
   visited[vertex] = 1
   for v in range(MAX_VERTICES):
      if adj[vertex][v] == 1 and visited[v] == 0:
         DFS(v)
   topological_order.append(vertex)

def topological_sort():
   for v in range(MAX_VERTICES):
      if visited[v] == 0:
         DFS(v)

def print_topological_order():
   print("Topological Order:", end=" ")
   for i in range(len(topological_order) - 1, -1, -1):
      print(topological_order[i], end=" ")
   print()

topological_sort()
print_topological_order()

Output

Topological Order: 0 2 1 3 4 5

Time Complexity of Topological Sort

When using Depth First Search (DFS) for topological sorting, the time complexity is O(V + E), where V is the number of vertices and E is the number of edges in the graph. This is because we visit each node once and explore all its edges.

Applications of Topological Sort

Topological sorting has many applications in various fields. Some of the applications of topological sort are:

  • Task Scheduling: Used to schedule tasks based on dependencies. Each task is a node, and dependencies are edges. This ensures tasks are executed in the correct order.
  • Course Prerequisites: Helps in deciding the order of taking courses. Courses are nodes, and prerequisites are edges, ensuring prerequisites are completed first.
  • Build Systems: Used in software build processes to determine the correct sequence for compiling files based on dependencies.
  • Network Routing: Helps in routing packets through a network by determining the correct order of processing based on connections between routers.
Advertisements