Understanding the Topological Sort algorithm

ยท

3 min read

Topological Sort is a linear ordering of vertices in a directed acyclic graph (DAG) such that for every directed edge ๐‘ขโ†’๐‘ฃ, vertex ๐‘ข comes before ๐‘ฃ in the ordering. This pattern is particularly useful in problems involving scheduling, dependency resolution, and various other applications where tasks or events have dependencies that must be respected.

Process

  1. Initialization: Create an array inDegree to count each vertex's incoming edges (in degrees). Create a list of lists graph to represent the graph. Each index of the list corresponds to a vertex, and the value at that index is a list of its children.

  2. Build the Graph and Count in degrees: Add edges to the graph from the input. For each edge (A -> B):

    1. Add B to the list of children for vertex A in the graph.

    2. Increment the count in the inDegree array for vertex B (since it has an incoming edge from A).

  3. Find Sources (Vertices with 0 In-degrees): Iterate through the inDegree array. Any vertex with an in-degree of 0 is a source. Store these sources in a Queue.

  4. Topological Sort: Start with the sources in the queue. For each source:

    1. Remove it from the queue.

    2. Add it to a sorted list sortedOrder.

    3. Look at its children in the graph.

    4. Decrease the in-degree of each child by 1.

    5. If any child's in-degree becomes 0, add it to the sources queue.

    6. Continue this process until the sources queue is empty.

  5. Termination: The process terminates when the queue is empty. If the sortedOrder list contains all vertices, the sort is successful. If any vertices are left unprocessed, the graph contains a cycle, and a topological sort is impossible.

When to Use

  1. Task Scheduling: To determine the order in which tasks should be performed when tasks have dependencies.

  2. Dependency Resolution: To resolve dependencies between modules or packages in a software system.

  3. Course Scheduling: To determine the order in which courses should be taken when courses have prerequisites.

Time Complexity

The topological sort algorithm has a time complexity of 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 each edge is processed exactly once.

Implementation

import java.util.*;

public class TopologicalSort {
    public static List<Integer> topologicalSort(int vertices, List<List<Integer>> edges) {
        List<Integer> sortedOrder = new ArrayList<>();

        if (vertices <= 0) {
            return sortedOrder;
        }

        // 1. Initialize the graph
        // count incoming edges
        int[] inDegree = new int[vertices];
        // adjacency list graph
        List<List<Integer>> graph = new ArrayList<>();
        for (int i = 0; i < vertices; i++) {
            graph.add(new ArrayList<>());
        }

        // 2. Build the graph
        for (List<Integer> edge : edges) {
            int parent = edge.get(0);
            int child = edge.get(1);
            // put the child into its parent's list
            graph.get(parent).add(child);
            // increment child's inDegree
            inDegree[child]++;
        }

        // 3. Find all sources/vertices with 0 inDegrees
        Queue<Integer> sources = new LinkedList<>();
        for (int i = 0; i < inDegree.length; i++) {
            if (inDegree[i] == 0) {
                sources.add(i);
            }
        }

        // 4. For each source, add it to sortedOrder and decrement its children inDegree
        // if a child becomes 0, add to source queue
        while (!sources.isEmpty()) {
            int vertex = sources.poll();
            sortedOrder.add(vertex);
            for (int child : graph.get(vertex)) {
                // get the nodes children to decrement their inDegree
                inDegree[child]--;
                if (inDegree[child] == 0) {
                    sources.add(child);
                }
            }
        }

        // topological sort is not possible as the graph has a cycle
        if (sortedOrder.size() != vertices) {
            return new ArrayList<>();
        }

        return sortedOrder;
    }

    public static void main(String[] args) {
        int vertices = 4;
        List<List<Integer>> edges = new ArrayList<>();
        edges.add(Arrays.asList(0, 1));
        edges.add(Arrays.asList(0, 2));
        edges.add(Arrays.asList(2, 3));
        edges.add(Arrays.asList(1, 3));

        List<Integer> sortedOrder = topologicalSort(vertices, edges);

        if (sortedOrder.isEmpty()) {
            System.out.println("Graph has a cycle, topological sorting is not possible.");
        } else {
            System.out.println("Topological Sort: " + sortedOrder);
        }
    }
}

Example problem for better understanding

Course Schedule

Thank you for reading!

You can support me by buying me a book.

ย