name: Topological Sort
slug: topological-sort
difficulty_level: 3
pattern_type: algorithm
display_order: 22

description: >
  Order vertices in a directed acyclic graph (DAG) such that for every
  edge u -> v, vertex u comes before v in the ordering.

when_to_use: |
  - Course prerequisites / task dependencies
  - Build order / compilation order
  - Detecting cycles in directed graphs
  - Any problem with "do A before B" constraints

metaphor: |
  Imagine getting dressed: you must put on underwear before pants, socks
  before shoes. Topological sort finds a valid order that respects all
  "must come before" rules. If there's a cycle (shirt requires jacket,
  jacket requires shirt), no valid order exists.

core_concept: |
  Two main approaches:

  **Kahn's Algorithm (BFS):** Start with nodes having no incoming edges
  (in-degree 0). Process them, remove their edges, repeat. If all nodes
  processed, valid order exists.

  **DFS-based:** Do DFS, add nodes to result when backtracking (post-order).
  Reverse at end. Cycle exists if we revisit a node in current path.

code_template: |
  from collections import deque

  def topological_sort_bfs(n: int, edges: list[tuple[int, int]]) -> list[int]:
      """Kahn's algorithm - returns empty list if cycle exists."""
      # Build adjacency list and in-degree count
      graph = [[] for _ in range(n)]
      in_degree = [0] * n

      for u, v in edges:  # u -> v (u must come before v)
          graph[u].append(v)
          in_degree[v] += 1

      # Start with nodes having no prerequisites
      queue = deque([i for i in range(n) if in_degree[i] == 0])
      result = []

      while queue:
          node = queue.popleft()
          result.append(node)

          for neighbor in graph[node]:
              in_degree[neighbor] -= 1
              if in_degree[neighbor] == 0:
                  queue.append(neighbor)

      # If we processed all nodes, valid topological order exists
      return result if len(result) == n else []

recognition_signals:
  - "prerequisites"
  - "dependencies"
  - "ordering tasks"
  - "course schedule"
  - "build order"
  - "detect cycle in directed graph"
  - "do X before Y"

common_mistakes:
  - title: Forgetting Cycle Detection
    description: |
      Assuming input is always a valid DAG. Must check if all nodes were
      processed (BFS) or if back-edge exists (DFS).
    fix: |
      BFS: Check `len(result) == n`. DFS: Track "visiting" state separately
      from "visited."

  - title: Wrong Edge Direction
    description: |
      Confusing "A depends on B" vs "A must come before B." These are
      opposite edge directions.
    fix: |
      Clarify: If A depends on B, edge is B -> A (B comes before A).

variations:
  - name: Course Schedule (cycle detection)
    description: Return true/false if valid ordering exists
    example: "course-schedule"
  - name: Course Schedule II (find order)
    description: Return the actual ordering
    example: "course-schedule-ii"
  - name: Alien Dictionary
    description: Infer ordering from sorted alien words
    example: "alien-dictionary"

related_patterns:
  - bfs
  - dfs

prerequisite_patterns:
  - bfs
  - dfs
