Given a directed acyclic graph (DAG), print it in Topological order using Kahn’s Topological Sort algorithm. If the DAG has more than one topological ordering, print any of them.





A Topological Sort or Topological Ordering of a directed graph is a linear ordering of its vertices such that for every directed edge uv from vertex u to vertex v, u comes before v in the ordering. A topological ordering is possible if and only if the graph has no directed cycles, i.e. if the graph is DAG.



For example, consider below graph:

Above graph has many valid topological ordering of vertices like,



7, 5, 3, 1, 4, 2, 0, 6

7, 5, 1, 2, 3, 4, 0, 6

5, 7, 3, 1, 0, 2, 6, 4

3, 5, 7, 0, 1, 2, 6, 4

5, 7, 3, 0, 1, 4, 6, 2

7, 5, 1, 3, 4, 0, 6, 2

5, 7, 1, 2, 3, 0, 6, 4

3, 7, 0, 5, 1, 4, 2, 6



.. and many more



Note that for every directed edge u -> v, u comes before v in the ordering. For example, the pictorial representation of the topological order [7, 5, 3, 1, 4, 2, 0, 6] is:







In the previous post, we have seen how to print topological order of a graph using Depth First Search (DFS) algorithm. In this post, Kahn’s Topological Sort algorithm is introduced which provides an efficient way to print topological order of a graph.



Kahn’s Topological Sort Algorithm works by finding vertices which have no incoming edges and removing all outgoing edges from these vertices. Below is psedocode for Kahn’s Topological Sort Algorithm taken from Wikipedia –





Kahn’s-Algorithm (graph)



L -> Empty list that will contain the sorted elements

S -> Set of all vertices with no incoming edges (i.e. having indegree 0)



while S is non-empty do

remove a vertex n from S

add n to tail of L

for each vertex m with an edge e from n to m do

remove edge e from the graph

if m has no other incoming edges then

insert m into S



if graph has edges then

return report “graph has at least one cycle”

else

return L “a topologically sorted order”





Note that a DAG has at least one such vertex which has no incoming edges.

How can we remove an edge from the graph or check if a vertex has no other incoming edge in constant time?



The idea is to maintain in-degree information of all graph vertices in a map or an array (say indegree[] ) for constant time operations. Here, indegree[m] will store number of incoming edges to vertex m.

If vertex m has no incoming edge and is ready to get processed, its indegree will be 0 i.e. indegree[m] = 0 .



. To remove an edge from n to m from the graph, we decrement indegree[m] by 1.



Below is C++, Java and Python implementation of Kahn’s Topological Sort Algorithm:



C++ #include <iostream> #include <vector> using namespace std; // Data structure to store graph edges struct Edge { int src, dest; }; // Class to represent a graph object class Graph { public: // construct a vector of vectors to represent an adjacency list vector<vector<int>> adjList; // stores indegree of a vertex vector<int> indegree; // Graph Constructor Graph(vector<Edge> const &edges, int N) { // resize the vector to N elements of type vector<int> adjList.resize(N); // initialize indegree vector<int> temp(N, 0); indegree = temp; // add edges to the directed graph for (auto &edge: edges) { // add an edge from source to destination adjList[edge.src].push_back(edge.dest); // increment in-degree of destination vertex by 1 indegree[edge.dest]++; } } }; // performs Topological Sort on a given DAG bool doTopologicalSort(Graph const &graph, vector<int> &L, int N) { vector<int> indegree = graph.indegree; // Set of all nodes with no incoming edges vector<int> S; for (int i = 0; i < N; i++) { if (!indegree[i]) { S.push_back(i); } } while (!S.empty()) { // remove a node n from S int n = S.back(); S.pop_back(); // add n to tail of L L.push_back(n); for (int m : graph.adjList[n]) { // remove edge from n to m from the graph indegree[m] -= 1; // if m has no other incoming edges then // insert m into S if (!indegree[m]) { S.push_back(m); } } } // if graph has edges then graph has at least one cycle for (int i = 0; i < N; i++) { if (indegree[i]) { return false; } } return true; } int main() { // vector of graph edges as per above diagram vector<Edge> edges = { { 0, 6 }, { 1, 2 }, { 1, 4 }, { 1, 6 }, { 3, 0 }, { 3, 4 }, { 5, 1 }, { 7, 0 }, { 7, 1 } }; // Number of nodes in the graph int N = 8; // create a graph from edges Graph graph(edges, N); // Empty list that will contain the sorted elements vector<int> L; // Perform Topological Sort if (doTopologicalSort(graph, L, N)) { // print topological order for (int i: L) cout << i << " "; } else { cout << "Graph has at least one cycle. " "Topological sorting is not possible"; } return 0; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 #include <iostream> #include <vector> using namespace std ; // Data structure to store graph edges struct Edge { int src , dest ; } ; // Class to represent a graph object class Graph { public : // construct a vector of vectors to represent an adjacency list vector < vector < int >> adjList ; // stores indegree of a vertex vector < int > indegree ; // Graph Constructor Graph ( vector < Edge > const &edges , int N ) { // resize the vector to N elements of type vector<int> adjList . resize ( N ) ; // initialize indegree vector < int > temp ( N , 0 ) ; indegree = temp ; // add edges to the directed graph for ( auto &edge : edges ) { // add an edge from source to destination adjList [ edge . src ] . push_back ( edge . dest ) ; // increment in-degree of destination vertex by 1 indegree [ edge . dest ] ++ ; } } } ; // performs Topological Sort on a given DAG bool doTopologicalSort ( Graph const &graph , vector < int > &L , int N ) { vector < int > indegree = graph . indegree ; // Set of all nodes with no incoming edges vector < int > S ; for ( int i = 0 ; i < N ; i ++ ) { if ( ! indegree [ i ] ) { S . push_back ( i ) ; } } while ( ! S . empty ( ) ) { // remove a node n from S int n = S . back ( ) ; S . pop_back ( ) ; // add n to tail of L L . push_back ( n ) ; for ( int m : graph . adjList [ n ] ) { // remove edge from n to m from the graph indegree [ m ] -= 1 ; // if m has no other incoming edges then // insert m into S if ( ! indegree [ m ] ) { S . push_back ( m ) ; } } } // if graph has edges then graph has at least one cycle for ( int i = 0 ; i < N ; i ++ ) { if ( indegree [ i ] ) { return false ; } } return true ; } int main ( ) { // vector of graph edges as per above diagram vector < Edge > edges = { { 0 , 6 } , { 1 , 2 } , { 1 , 4 } , { 1 , 6 } , { 3 , 0 } , { 3 , 4 } , { 5 , 1 } , { 7 , 0 } , { 7 , 1 } } ; // Number of nodes in the graph int N = 8 ; // create a graph from edges Graph graph ( edges , N ) ; // Empty list that will contain the sorted elements vector < int > L ; // Perform Topological Sort if ( doTopologicalSort ( graph , L , N ) ) { // print topological order for ( int i : L ) cout << i << " " ; } else { cout << "Graph has at least one cycle. " "Topological sorting is not possible" ; } return 0 ; } Download Run Code Output:



7 5 1 2 3 4 0 6

Java import java.util.*; // data structure to store graph edges class Edge { int source, dest; public Edge(int source, int dest) { this.source = source; this.dest = dest; } } // class to represent a graph object class Graph { // A List of Lists to represent an adjacency list List<List<Integer>> adjList = null; // stores indegree of a vertex List<Integer> indegree = null; // Constructor Graph(List<Edge> edges, int N) { adjList = new ArrayList<>(); for (int i = 0; i < N; i++) { adjList.add(new ArrayList<>()); } // initialize indegree of each vertex by 0 indegree = new ArrayList<>(Collections.nCopies(N, 0)); // add edges to the undirected graph for (Edge edge: edges) { int src = edge.source; int dest = edge.dest; // add an edge from source to destination adjList.get(src).add(dest); // increment in-degree of destination vertex by 1 indegree.set(dest, indegree.get(dest) + 1); } } } class Main { // performs Topological Sort on a given DAG public static List<Integer> doTopologicalSort(Graph graph, int N) { // list to store the sorted elements List<Integer> L = new ArrayList<>(); // get indegree information of the graph List<Integer> indegree = graph.indegree; // Set of all nodes with no incoming edges Stack<Integer> S = new Stack<>(); for (int i = 0; i < N; i++) { if (indegree.get(i) == 0) { S.add(i); } } while (!S.isEmpty()) { // remove a node n from S int n = S.pop(); // add n to tail of L L.add(n); for (int m : graph.adjList.get(n)) { // remove edge from n to m from the graph indegree.set(m, indegree.get(m) - 1); // if m has no other incoming edges then // insert m into S if (indegree.get(m) == 0) { S.add(m); } } } // if graph has edges then graph has at least one cycle for (int i = 0; i < N; i++) { if (indegree.get(i) != 0) { return null; } } return L; } public static void main(String[] args) { // List of graph edges as per above diagram List<Edge> edges = Arrays.asList( new Edge(0, 6), new Edge(1, 2), new Edge(1, 4), new Edge(1, 6), new Edge(3, 0), new Edge(3, 4), new Edge(5, 1), new Edge(7, 0), new Edge(7, 1) ); // Set number of vertices in the graph final int N = 8; // create a graph from edges Graph graph = new Graph(edges, N); // Perform Topological Sort List<Integer> L = doTopologicalSort(graph, N); if (L != null) { System.out.print(L); // print topological order } else { System.out.println("Graph has at least one cycle. " + "Topological sorting is not possible"); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 import java . util . * ; // data structure to store graph edges class Edge { int source , dest ; public Edge ( int source , int dest ) { this . source = source ; this . dest = dest ; } } // class to represent a graph object class Graph { // A List of Lists to represent an adjacency list List < List <Integer> > adjList = null ; // stores indegree of a vertex List <Integer> indegree = null ; // Constructor Graph ( List <Edge> edges , int N ) { adjList = new ArrayList <> ( ) ; for ( int i = 0 ; i < N ; i ++ ) { adjList . add ( new ArrayList <> ( ) ) ; } // initialize indegree of each vertex by 0 indegree = new ArrayList <> ( Collections . nCopies ( N , 0 ) ) ; // add edges to the undirected graph for ( Edge edge : edges ) { int src = edge . source ; int dest = edge . dest ; // add an edge from source to destination adjList . get ( src ) . add ( dest ) ; // increment in-degree of destination vertex by 1 indegree . set ( dest , indegree . get ( dest ) + 1 ) ; } } } class Main { // performs Topological Sort on a given DAG public static List <Integer> doTopologicalSort ( Graph graph , int N ) { // list to store the sorted elements List <Integer> L = new ArrayList <> ( ) ; // get indegree information of the graph List <Integer> indegree = graph . indegree ; // Set of all nodes with no incoming edges Stack <Integer> S = new Stack <> ( ) ; for ( int i = 0 ; i < N ; i ++ ) { if ( indegree . get ( i ) == 0 ) { S . add ( i ) ; } } while ( ! S . isEmpty ( ) ) { // remove a node n from S int n = S . pop ( ) ; // add n to tail of L L . add ( n ) ; for ( int m : graph . adjList . get ( n ) ) { // remove edge from n to m from the graph indegree . set ( m , indegree . get ( m ) - 1 ) ; // if m has no other incoming edges then // insert m into S if ( indegree . get ( m ) == 0 ) { S . add ( m ) ; } } } // if graph has edges then graph has at least one cycle for ( int i = 0 ; i < N ; i ++ ) { if ( indegree . get ( i ) != 0 ) { return null ; } } return L ; } public static void main ( String [ ] args ) { // List of graph edges as per above diagram List <Edge> edges = Arrays . asList ( new Edge ( 0 , 6 ) , new Edge ( 1 , 2 ) , new Edge ( 1 , 4 ) , new Edge ( 1 , 6 ) , new Edge ( 3 , 0 ) , new Edge ( 3 , 4 ) , new Edge ( 5 , 1 ) , new Edge ( 7 , 0 ) , new Edge ( 7 , 1 ) ) ; // Set number of vertices in the graph final int N = 8 ; // create a graph from edges Graph graph = new Graph ( edges , N ) ; // Perform Topological Sort List <Integer> L = doTopologicalSort ( graph , N ) ; if ( L != null ) { System . out . print ( L ) ; // print topological order } else { System . out . println ( "Graph has at least one cycle. " + "Topological sorting is not possible" ) ; } } } Download Run Code Output:



[7, 5, 1, 2, 3, 4, 0, 6]

Python from collections import deque # class to represent a graph object: class Graph: # stores indegree of a vertex indegree = None # Constructor def __init__(self, edges, N): # A List of Lists to represent an adjacency list self.adjList = [[] for _ in range(N)] # initialize indegree of each vertex by 0 self.indegree = [0] * N # add edges to the undirected graph for (src, dest) in edges: # add an edge from source to destination self.adjList[src].append(dest) # increment in-degree of destination vertex by 1 self.indegree[dest] = self.indegree[dest] + 1 # performs Topological Sort on a given DAG def doTopologicalSort(graph, N): # list to store the sorted elements L = [] # get in-degree information of the graph indegree = graph.indegree # Set of all nodes with no incoming edges S = deque([i for i in range(N) if indegree[i] == 0]) while S: # remove a node n from S n = S.pop() # add n to tail of L L.append(n) for m in graph.adjList[n]: # remove edge from n to m from the graph indegree[m] = indegree[m] - 1 # if m has no other incoming edges then # insert m into S if indegree[m] == 0: S.append(m) # if graph has edges then graph has at least one cycle for i in range(N): if indegree[i]: return None return L if __name__ == '__main__': # List of graph edges as per above diagram edges = [(0, 6), (1, 2), (1, 4), (1, 6), (3, 0), (3, 4), (5, 1), (7, 0), (7, 1)] # Set number of vertices in the graph N = 8 # create a graph from edges graph = Graph(edges, N) # Perform Topological Sort L = doTopologicalSort(graph, N) if L: print(L) # print topological order else: print("Graph has at least one cycle. Topological sorting is not possible.") 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 from collections import deque # class to represent a graph object: class Graph : # stores indegree of a vertex indegree = None # Constructor def __init__ ( self , edges , N ) : # A List of Lists to represent an adjacency list self . adjList = [ [ ] for _ in range ( N ) ] # initialize indegree of each vertex by 0 self . indegree = [ 0 ] * N # add edges to the undirected graph for ( src , dest ) in edges : # add an edge from source to destination self . adjList [ src ] . append ( dest ) # increment in-degree of destination vertex by 1 self . indegree [ dest ] = self . indegree [ dest ] + 1 # performs Topological Sort on a given DAG def doTopologicalSort ( graph , N ) : # list to store the sorted elements L = [ ] # get in-degree information of the graph indegree = graph . indegree # Set of all nodes with no incoming edges S = deque ( [ i for i in range ( N ) if indegree [ i ] == 0 ] ) while S : # remove a node n from S n = S . pop ( ) # add n to tail of L L . append ( n ) for m in graph . adjList [ n ] : # remove edge from n to m from the graph indegree [ m ] = indegree [ m ] - 1 # if m has no other incoming edges then # insert m into S if indegree [ m ] == 0 : S . append ( m ) # if graph has edges then graph has at least one cycle for i in range ( N ) : if indegree [ i ] : return None return L if __name__ == '__main__' : # List of graph edges as per above diagram edges = [ ( 0 , 6 ) , ( 1 , 2 ) , ( 1 , 4 ) , ( 1 , 6 ) , ( 3 , 0 ) , ( 3 , 4 ) , ( 5 , 1 ) , ( 7 , 0 ) , ( 7 , 1 ) ] # Set number of vertices in the graph N = 8 # create a graph from edges graph = Graph ( edges , N ) # Perform Topological Sort L = doTopologicalSort ( graph , N ) if L : print ( L ) # print topological order else : print ( "Graph has at least one cycle. Topological sorting is not possible." ) Download Run Code Output:



[7, 5, 1, 2, 3, 4, 0, 6]







Time complexity of Kahn’s Topological Sort Algorithm is O(n + m) where n is number of vertices and m is number of edges in the graph.



References: https://en.wikipedia.org/wiki/Topological_sorting#Kahn.27s_algorithm









(14 votes, average: 4.43 out of 5)

Loading...

Thanks for reading.