Topological Sorting

Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every directed edge uv, vertex u comes before v in the ordering. Topological Sorting for a graph is not possible if the graph is not a DAG.

For example, a topological sorting of the following graph is “5 4 2 3 1 0″. There can be more than one topological sorting for a graph. For example, another topological sorting of the following graph is “4 5 2 3 1 0″. The first vertex in topological sorting is always a vertex with in-degree as 0 (a vertex with no in-coming edges).

graph

Topological Sorting vs Depth First Traversal (DFS):
In DFS, we print a vertex and then recursively call DFS for its adjacent vertices. In topological sorting, we need to print a vertex before its adjacent vertices. For example, in the given graph, the vertex ‘5’ should be printed before vertex ‘0’, but unlike DFS, the vertex ‘4’ should also be printed before vertex ‘0’. So Topological sorting is different from DFS. For example, a DFS of the above graph is “5 2 3 1 0 4″, but it is not a topological sorting

Algorithm to find Topological Sorting:
We recommend to first see implementation of DFS here. We can modify DFS to find Topological Sorting of a graph. In DFS, we start from a vertex, we first print it and then recursively call DFS for its adjacent vertices. In topological sorting, we use a temporary stack. We don’t print the vertex immediately, we first recursively call topological sorting for all its adjacent vertices, then push it to a stack. Finally, print contents of stack. Note that a vertex is pushed to stack only when all of its adjacent vertices (and their adjacent vertices and so on) are already in stack.

Following are C++ and Java implementations of topological sorting. Please see the code for Depth First Traversal for a disconnected Graph and note the differences between the second code given there and the below code.

C++

// A C++ program to print topological sorting of a DAG
#include<iostream>
#include <list>
#include <stack>
using namespace std;

// Class to represent a graph
class Graph
{
    int V;    // No. of vertices'

    // Pointer to an array containing adjacency listsList
    list<int> *adj;

    // A function used by topologicalSort
    void topologicalSortUtil(int v, bool visited[], stack<int> &Stack);
public:
    Graph(int V);   // Constructor

     // function to add an edge to graph
    void addEdge(int v, int w);

    // prints a Topological Sort of the complete graph
    void topologicalSort();
};

Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}

void Graph::addEdge(int v, int w)
{
    adj[v].push_back(w); // Add w to v’s list.
}

// A recursive function used by topologicalSort
void Graph::topologicalSortUtil(int v, bool visited[], 
                                stack<int> &Stack)
{
    // Mark the current node as visited.
    visited[v] = true;

    // Recur for all the vertices adjacent to this vertex
    list<int>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
        if (!visited[*i])
            topologicalSortUtil(*i, visited, Stack);

    // Push current vertex to stack which stores result
    Stack.push(v);
}

// The function to do Topological Sort. It uses recursive 
// topologicalSortUtil()
void Graph::topologicalSort()
{
    stack<int> Stack;

    // Mark all the vertices as not visited
    bool *visited = new bool[V];
    for (int i = 0; i < V; i++)
        visited[i] = false;

    // Call the recursive helper function to store Topological
    // Sort starting from all vertices one by one
    for (int i = 0; i < V; i++)
      if (visited[i] == false)
        topologicalSortUtil(i, visited, Stack);

    // Print contents of stack
    while (Stack.empty() == false)
    {
        cout << Stack.top() << " ";
        Stack.pop();
    }
}

// Driver program to test above functions
int main()
{
    // Create a graph given in the above diagram
    Graph g(6);
    g.addEdge(5, 2);
    g.addEdge(5, 0);
    g.addEdge(4, 0);
    g.addEdge(4, 1);
    g.addEdge(2, 3);
    g.addEdge(3, 1);

    cout << "Following is a Topological Sort of the given graph \n";
    g.topologicalSort();

    return 0;
}

Java

// A Java program to print topological sorting of a DAG
import java.io.*;
import java.util.*;

// This class represents a directed graph using adjacency
// list representation
class Graph
{
    private int V;   // No. of vertices
    private LinkedList<Integer> adj[]; // Adjacency List

    //Constructor
    Graph(int v)
    {
        V = v;
        adj = new LinkedList[v];
        for (int i=0; i<v; ++i)
            adj[i] = new LinkedList();
    }

    // Function to add an edge into the graph
    void addEdge(int v,int w) { adj[v].add(w); }

    // A recursive function used by topologicalSort
    void topologicalSortUtil(int v, boolean visited[],
                             Stack stack)
    {
        // Mark the current node as visited.
        visited[v] = true;
        Integer i;

        // Recur for all the vertices adjacent to this
        // vertex
        Iterator<Integer> it = adj[v].iterator();
        while (it.hasNext())
        {
            i = it.next();
            if (!visited[i])
                topologicalSortUtil(i, visited, stack);
        }

        // Push current vertex to stack which stores result
        stack.push(new Integer(v));
    }

    // The function to do Topological Sort. It uses
    // recursive topologicalSortUtil()
    void topologicalSort()
    {
        Stack stack = new Stack();

        // Mark all the vertices as not visited
        boolean visited[] = new boolean[V];
        for (int i = 0; i < V; i++)
            visited[i] = false;

        // Call the recursive helper function to store
        // Topological Sort starting from all vertices
        // one by one
        for (int i = 0; i < V; i++)
            if (visited[i] == false)
                topologicalSortUtil(i, visited, stack);

        // Print contents of stack
        while (stack.empty()==false)
            System.out.print(stack.pop() + " ");
    }

    // Driver method
    public static void main(String args[])
    {
        // Create a graph given in the above diagram
        Graph g = new Graph(6);
        g.addEdge(5, 2);
        g.addEdge(5, 0);
        g.addEdge(4, 0);
        g.addEdge(4, 1);
        g.addEdge(2, 3);
        g.addEdge(3, 1);

        System.out.println("Following is a Topological " +
                           "sort of the given graph");
        g.topologicalSort();
    }
}
// This code is contributed by Aakash Hasija


Output:
Following is a Topological Sort of the given graph
5 4 2 3 1 0

Time Complexity: The above algorithm is simply DFS with an extra stack. So time complexity is same as DFS which is O(V+E).

Applications:
Topological Sorting is mainly used for scheduling jobs from the given dependencies among jobs. In computer science, applications of this type arise in instruction scheduling, ordering of formula cell evaluation when recomputing formula values in spreadsheets, logic synthesis, determining the order of compilation tasks to perform in makefiles, data serialization, and resolving symbol dependencies in linkers [2].

Related Articles:
Kahn’s algorithm for Topological Sorting : Another O(V + E) algorithm.
All Topological Sorts of a Directed Acyclic Graph

References:
http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/topoSort.htm
http://en.wikipedia.org/wiki/Topological_sorting

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above



Company Wise Coding Practice    Topic Wise Coding Practice





Writing code in comment? Please use code.geeksforgeeks.org, generate link and share the link here.

  • student

    This question on SPOJ http://www.spoj.com/problems/PFDEP/ requires topological sorting but in a unique way of listing tasks in ascending order based on their number as soon as their dependency is met.
    Solution: http://ideone.com/iH8yVe

    I was asked a similar question in Microsoft’s interview.

  • Wellwisher
  • Zheng Luo

    Thanks for sharing, I think we can regard this approach as the post order traversal of a DAG.

  • DarKProtocol

    How come 4 is present in the output..? there is no path to reach 4.. can any one explain?

    • Ronny Mandal

      This is perhaps late, but: topological sort always starts with the nodes that have the smallest in-degree. In this graph it is 4 and 5, both have an in-degree of zero. Node 2 and 3 have one and node 0 and 1 have two.

      • Jeremy Shi

        more precisely, always starts with the nodes that has zero in-degree.

  • Romel

    Thanks for writing this post! :)

  • Setu

    The above approach gives a topological sort order if the graph is a DAG, In case if the graph is not a DAG, it does not intimate that the graph is a DAG.

    Please refer to the code below –

    Any comments are welcome if some thing is wrong…

    package com.samplePackage;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Stack;

    public class TopologicalSort {

    public static void main(String[] args) {
    Graph g = new Graph(6);
    g.addEdge(5, 2);
    g.addEdge(5, 0);
    g.addEdge(4, 0);
    g.addEdge(4, 1);
    g.addEdge(2, 3);
    g.addEdge(3, 1);
    g.addEdge(0, 3);

    g.TopSort();
    }

    }
    class Graph{

    private int vertexCount;
    private List []adjcentList ;

    Graph(int vertexCount)
    {
    this.vertexCount=vertexCount;
    this.adjcentList= new ArrayList [vertexCount];
    }

    public void TopSort()
    {
    int [] visited= new int[this.vertexCount];
    Stack stack = new Stack();

    for(int i =0; i< this.vertexCount;i++)
    visited[i]=0;

    for(int i =0; i< this.vertexCount;i++)
    if(visited[i]==0 && visited[i]!=2)
    TopSortUtils(i,visited,stack);

    while(!stack.isEmpty())
    System.out.println(stack.pop());
    }

    public void TopSortUtils(int vertex , int [] visited, Stack stack)
    {
    if(visited[vertex]==1)
    {
    System.out.println(“Since the graph is not a DAG, No Topological Sort order.”);
    System.exit(0);
    }
    if(visited[vertex]!=2)
    {
    visited[vertex]=1;

    if(this.adjcentList[vertex]!=null)
    for(int i : this.adjcentList[vertex])
    TopSortUtils(i, visited, stack);

    visited[vertex]=2;
    stack.push(vertex);
    }
    }

    void addEdge(int u, int v)
    {
    if (null ==this.adjcentList[u])
    this.adjcentList[u]= new ArrayList();
    this.adjcentList[u].add(v);
    }

    }

  • sdg

    Topological Sort with a different approach. Kindly comment in case of any bugs.

    #include

    #include

    #include

    int *s, start, end, **graph,*l,*order;

    int init(int no_of_vertices){

    int i;

    start = 0;

    end = 0;

    graph = (int **)calloc(no_of_vertices,sizeof(int));

    for(i = 0; i < no_of_vertices; i++) {

    graph[i] = (int *)calloc(no_of_vertices,sizeof(int));

    memset(graph[i],0,sizeof(graph[i]));

    }

    /* Temporary set of nodes in the form of a queue */

    s = (int *)calloc(no_of_vertices,sizeof(bool));

    /* Sorted list */

    l = (int *)calloc(no_of_vertices,sizeof(int));

    order = (int *)calloc(no_of_vertices,sizeof(int));

    }

    void add_edge(int src,int dest) {

    if(graph){

    /* Valid because the graph is DAG */

    graph[src][dest] = 1;

    graph[dest][src] = -1;

    order[dest]++;

    }

    }

    void remove_edge(int src,int dest){

    if(graph) {

    graph[src][dest] = 0;

    graph[dest][src] = 0;

    if(order[dest])

    order[dest]--;

    }

    }

    int create_s(int no_of_vertices){

    int i,j,k = 0;

    bool has_incoming;

    for(i = 0; i < no_of_vertices; i++){

    if(!order[i])

    s[k++] = i;

    }

    return k;

    }

    void t_sort(int no_of_vertices){

    int start = 0,cur_node,j,k = 0, nodes;

    nodes = create_s(no_of_vertices);

    while(/* s is not empty */start < nodes){

    cur_node = s[start++];

    for(j = 0; j 0){

    remove_edge(cur_node,j);

    if(!order[j]){

    s[nodes++] = j;

    }

    }

    }

    l[k++] = cur_node;

    }

    }

    int main() {

    int no_of_vertices;

    printf("Enter the number of vertices : ");

    scanf("%d",&no_of_vertices);

    init(no_of_vertices);

    add_edge(0,3);

    add_edge(0,2);

    add_edge(4,3);

    add_edge(1,2);

    add_edge(1,7);

    add_edge(3,6);

    add_edge(3,5);

    add_edge(2,5);

    t_sort(no_of_vertices);

    for(int i = 0; i < no_of_vertices; i++)

    printf("%d ",l[i]);

    printf("n");

    return 0;

    }

  • coder22

    What would be the running time of this algorithm?
    o(VlgV) ?

    • adi

      O(v+e)

  • Zeb

    Here’s another example of a topological traversal. I use a slightly different graph structure here with no explicit ‘edges’ just nodes and children.

     
    #include <iostream>
    #include <vector>
    #include <stack>
    
    using namespace std;
    
    // Topological sort of graph DAG (directed acyclic graph)
    class Node
    {
    public:
    	vector<Node*> children;
    	char value;
    	bool visited;
    
    	Node(char value)
    	{
    		this->value = value;
    		this->visited = false;
    	}
    };
    
    stack<Node*> the_stack;
    
    void loadStackInTopologicalOrder(Node* root)
    {
    	for(int i = 0; i < root->children.size(); i++)
    	{
    		if(!root->children[i]->visited)
    		{
    			loadStackInTopologicalOrder(root->children[i]);
    		}
    	}
    	
    	the_stack.push(root);
    	root->visited = true;
    }
    
    int main()
    {
    	vector<Node*> graphNodes;
    
    	for(int i = 0; i <= 5; i++)
    	{
    		graphNodes.push_back(new Node('0' + i));
    	}
    	
    	for(int i = 0; i < graphNodes.size(); i++)
    	{
    		cout << graphNodes[i]->value << ", ";
    	}
    	cout << "\n";
    
    	// link some things together, no loops allowed!
    	graphNodes[2]->children.push_back(graphNodes[3]);
    	graphNodes[3]->children.push_back(graphNodes[1]);
    	graphNodes[4]->children.push_back(graphNodes[1]);
    	graphNodes[4]->children.push_back(graphNodes[0]);
    	graphNodes[5]->children.push_back(graphNodes[2]);
    	graphNodes[5]->children.push_back(graphNodes[0]);
    
    	for(int i = 0; i < graphNodes.size(); i++)
    	{
    		if(!graphNodes[i]->visited)
    		{
    			loadStackInTopologicalOrder(graphNodes[i]);
    		}
    	}
    
    	while(!the_stack.empty())
    	{
    		Node* node = the_stack.top();
    		cout << node->value << ", ";
    		the_stack.pop();
    	}
    	cout << "\n";
    
    	cin.get();
    }