{
    "slug": "topological_sort",
    "term": "Topological Sort",
    "category": "algorithms",
    "difficulty": "intermediate",
    "short": "An ordering of nodes in a directed acyclic graph (DAG) such that for every directed edge u→v, node u appears before v in the ordering.",
    "long": "Topological sort is only possible on directed acyclic graphs (DAGs) — any cycle makes a valid ordering impossible. Two common algorithms: Kahn's algorithm uses in-degree counts and a queue (BFS-based), and DFS-based sort uses recursive post-order traversal. Both run in O(V + E). The result is not unique — many valid orderings may exist. Real-world applications are everywhere: package/dependency managers (Composer, npm) use it to determine installation order, build systems (Make, Gradle) use it for task scheduling, course prerequisite systems, and database migration runners rely on it to apply schema changes in the right order.",
    "aliases": [
        "topo sort",
        "dependency ordering",
        "DAG ordering"
    ],
    "tags": [
        "algorithms",
        "graphs",
        "dag",
        "sorting",
        "dependencies",
        "computer-science"
    ],
    "misconception": "Topological sort works on any directed graph — it only works on DAGs. If a cycle exists (A→B→C→A) there is no valid topological ordering, and Kahn's algorithm will detect this because not all nodes will be processed (remaining in-degrees never reach zero).",
    "why_it_matters": "Any time you have tasks, packages, or migrations with dependencies, you need topological sort under the hood. Implementing a dependency resolver or build system without understanding it leads to brittle ad-hoc ordering logic that breaks on edge cases.",
    "common_mistakes": [
        "Not detecting cycles — silently returning a partial ordering when a cycle exists instead of throwing an error.",
        "Using topological sort on an undirected graph — the concept only applies to directed edges.",
        "Assuming the output order is unique — many valid orderings exist; tests should not depend on a specific one.",
        "Reinventing it manually with nested loops instead of using Kahn's or DFS — O(V²) instead of O(V+E)."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "graph_algorithms",
        "dijkstra_algorithm",
        "dependency_injection",
        "composer"
    ],
    "prerequisites": [
        "graph_algorithms",
        "big_o_notation"
    ],
    "refs": [
        "https://en.wikipedia.org/wiki/Topological_sorting"
    ],
    "bad_code": "// Naive: repeatedly scan for nodes with no unresolved deps — O(V²):\nfunction topoNaive(array $deps): array {\n    $resolved = [];\n    while (count($resolved) < count($deps)) {\n        $progress = false;\n        foreach ($deps as $node => $nodeDeps) {\n            if (!in_array($node, $resolved) &&\n                empty(array_diff($nodeDeps, $resolved))) {\n                $resolved[] = $node;\n                $progress = true;\n            }\n        }\n        if (!$progress) throw new RuntimeException('Cycle detected');\n    }\n    return $resolved;\n}",
    "good_code": "// Kahn's algorithm — O(V+E) with cycle detection:\nfunction topologicalSort(array $graph): array {\n    $inDegree = array_fill_keys(array_keys($graph), 0);\n    foreach ($graph as $neighbours) {\n        foreach ($neighbours as $v) $inDegree[$v]++;\n    }\n    $queue = array_keys(array_filter($inDegree, fn($d) => $d === 0));\n    $order = [];\n    while ($queue) {\n        $u = array_shift($queue);\n        $order[] = $u;\n        foreach ($graph[$u] as $v) {\n            if (--$inDegree[$v] === 0) $queue[] = $v;\n        }\n    }\n    if (count($order) !== count($graph)) {\n        throw new RuntimeException('Graph has a cycle — topological sort impossible');\n    }\n    return $order;\n}\n\n// Usage: ['a' => ['b','c'], 'b' => ['d'], 'c' => ['d'], 'd' => []]\n// Returns: ['a', 'b', 'c', 'd'] or ['a', 'c', 'b', 'd']",
    "example_note": "Kahn's naturally detects cycles — if `count($order) !== count($graph)` after processing, a cycle prevented some nodes from ever reaching in-degree zero.",
    "quick_fix": "Use Kahn's algorithm with an in-degree map and queue — O(V+E), detects cycles automatically",
    "severity": "low",
    "effort": "medium",
    "created": "2026-03-24",
    "updated": "2026-03-24",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/topological_sort",
        "html_url": "https://codeclaritylab.com/glossary/topological_sort",
        "json_url": "https://codeclaritylab.com/glossary/topological_sort.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Topological Sort](https://codeclaritylab.com/glossary/topological_sort) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/topological_sort"
            }
        }
    }
}