{
  "id": "graphs/topological-sort",
  "version": 1,
  "deterministic": true,
  "url": "/dsa/graphs/topological-sort",
  "topic": {
    "slug": "graphs",
    "title": "Graphs"
  },
  "title": "Topological Sort",
  "tagline": "Put jobs in an order where nothing happens before what it depends on.",
  "vizKind": "graph",
  "complexity": {
    "time": {
      "best": "O(V + E)",
      "average": "O(V + E)",
      "worst": "O(V + E)"
    },
    "space": "O(V)",
    "growth": "linear",
    "note": "Every job is queued once and every dependency arrow is followed once: V + E. The same cost as BFS or DFS — because underneath, that's exactly what it is."
  },
  "code": {
    "javascript": "function topoSort(graph) {\n  const indegree = {};\n  for (const v of graph.nodes) indegree[v] = 0;\n  for (const [u, v] of graph.edges) indegree[v]++;\n\n  // everything that depends on nothing can start now\n  const ready = graph.nodes.filter(v => indegree[v] === 0);\n  const order = [];\n\n  while (ready.length > 0) {\n    const u = ready.shift();\n    order.push(u);\n\n    for (const v of graph.next[u]) {\n      indegree[v]--;\n      if (indegree[v] === 0) ready.push(v);\n    }\n  }\n\n  if (order.length < graph.nodes.length) return null; // a cycle\n  return order;\n}",
    "python": "from collections import deque\n\ndef topo_sort(graph):\n    indeg = {v: 0 for v in graph}\n    for u in graph:\n        for v in graph[u]:\n            indeg[v] += 1\n\n    ready = deque(v for v in graph if indeg[v] == 0)\n    order = []\n\n    while ready:\n        u = ready.popleft()\n        order.append(u)\n\n        for v in graph[u]:\n            indeg[v] -= 1\n            if indeg[v] == 0:\n                ready.append(v)\n\n    return order if len(order) == len(graph) else None\n",
    "java": "List<String> topoSort(Graph g) {\n  Map<String,Integer> indeg = new HashMap<>();\n  for (String v : g.nodes) indeg.put(v, 0);\n  for (Edge e : g.edges) indeg.merge(e.to, 1, Integer::sum);\n\n  Deque<String> ready = new ArrayDeque<>();\n  for (String v : g.nodes) if (indeg.get(v) == 0) ready.add(v);\n  List<String> order = new ArrayList<>();\n\n  while (!ready.isEmpty()) {\n    String u = ready.pollFirst();\n    order.add(u);\n\n    for (String v : g.next.get(u)) {\n      indeg.merge(v, -1, Integer::sum);\n      if (indeg.get(v) == 0) ready.add(v);\n    }\n  }\n\n  return order.size() == g.nodes.size() ? order : null;\n}",
    "cpp": "vector<string> topoSort(Graph& g) {\n  map<string,int> indeg;\n  for (auto& v : g.nodes) indeg[v] = 0;\n  for (auto& [u, v] : g.edges) indeg[v]++;\n\n  queue<string> ready;\n  for (auto& v : g.nodes) if (indeg[v] == 0) ready.push(v);\n  vector<string> order;\n\n  while (!ready.empty()) {\n    string u = ready.front(); ready.pop();\n    order.push_back(u);\n\n    for (auto& v : g.next[u]) {\n      if (--indeg[v] == 0) ready.push(v);\n    }\n  }\n\n  if (order.size() < g.nodes.size()) return {}; // a cycle\n  return order;\n}"
  },
  "defaultInput": [
    1
  ],
  "defaultTarget": null,
  "inputHint": "The number on each node is how many jobs still block it — its in-degree.",
  "pitfalls": [
    {
      "wrong": "Running it on an undirected graph.",
      "right": "Topological order only means something when edges have direction. 'A before B' is a one-way claim; an undirected edge makes no such claim."
    },
    {
      "wrong": "Assuming there's one correct answer.",
      "right": "There are usually many valid orders. Socks-then-shirt and shirt-then-socks are both fine. Any order where every arrow points forwards is correct."
    },
    {
      "wrong": "Not checking whether every node made it into the order.",
      "right": "If some are left over, there's a cycle and no valid order exists. That check is not an afterthought — it's how you detect the impossible case."
    }
  ],
  "quiz": [
    {
      "q": "What does a node's in-degree of zero mean?",
      "options": [
        "It has no outgoing arrows",
        "Nothing blocks it — it can be done right now",
        "It's the last job",
        "It's part of a cycle"
      ],
      "answer": 1,
      "why": "In-degree counts arrows pointing *in* — the things that must happen first. Zero of them means nothing is blocking it, so it's ready to go."
    },
    {
      "q": "You run out of unblocked jobs but some jobs remain. What does that prove?",
      "options": [
        "The graph is very large",
        "The dependencies contain a cycle, so no valid order exists",
        "You started from the wrong node",
        "The algorithm has a bug"
      ],
      "answer": 1,
      "why": "Every remaining job is waiting on another remaining job — which can only happen if they wait on each other in a loop. The algorithm has just proved the task is impossible."
    },
    {
      "q": "How many valid topological orders does a graph usually have?",
      "options": [
        "Exactly one",
        "Usually many",
        "None",
        "Exactly two"
      ],
      "answer": 1,
      "why": "Any order where every arrow points forwards is valid, and there are normally several. Socks before shoes matters; socks before shirt doesn't."
    }
  ],
  "problems": [
    {
      "name": "Course Schedule",
      "difficulty": "Medium",
      "url": "https://leetcode.com/problems/course-schedule/"
    },
    {
      "name": "Course Schedule II",
      "difficulty": "Medium",
      "url": "https://leetcode.com/problems/course-schedule-ii/"
    },
    {
      "name": "Find Eventual Safe States",
      "difficulty": "Medium",
      "url": "https://leetcode.com/problems/find-eventual-safe-states/"
    }
  ],
  "trace": {
    "note": "Each frame is one immutable step: data snapshot, pointers, per-index roles, executing code line, and a one-sentence explanation.",
    "length": 17,
    "frames": [
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12
            },
            {
              "id": "trousers",
              "label": "trousers 1",
              "x": 0.38,
              "y": 0.6
            },
            {
              "id": "belt",
              "label": "belt 2",
              "x": 0.64,
              "y": 0.4
            },
            {
              "id": "shoes",
              "label": "shoes 2",
              "x": 0.64,
              "y": 0.85
            },
            {
              "id": "jacket",
              "label": "jacket 2",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers"
            },
            {
              "from": "trousers",
              "to": "belt"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": []
          },
          "visited": []
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 4,
        "variables": {
          "note": "number on each node = jobs still blocking it"
        },
        "explanation": "Getting dressed: some things must come before others. The arrow under → trousers means underwear goes on first. The number on each node counts how many things still block it — its in-degree.",
        "stats": {
          "comparisons": 0,
          "swaps": 0
        },
        "accent": "compare"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "pivot"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "pivot"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "pivot"
            },
            {
              "id": "trousers",
              "label": "trousers 1",
              "x": 0.38,
              "y": 0.6
            },
            {
              "id": "belt",
              "label": "belt 2",
              "x": 0.64,
              "y": 0.4
            },
            {
              "id": "shoes",
              "label": "shoes 2",
              "x": 0.64,
              "y": 0.85
            },
            {
              "id": "jacket",
              "label": "jacket 2",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers"
            },
            {
              "from": "trousers",
              "to": "belt"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "socks",
              "under",
              "shirt"
            ]
          },
          "visited": []
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 7,
        "variables": {
          "ready": "socks under shirt"
        },
        "explanation": "Anything with a 0 is blocked by nothing, so it can go on right now: socks, under, shirt. Those are our starting points.",
        "stats": {
          "comparisons": 0,
          "swaps": 0
        },
        "accent": "pivot"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "pivot"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "pivot"
            },
            {
              "id": "trousers",
              "label": "trousers 1",
              "x": 0.38,
              "y": 0.6
            },
            {
              "id": "belt",
              "label": "belt 2",
              "x": 0.64,
              "y": 0.4
            },
            {
              "id": "shoes",
              "label": "shoes 2",
              "x": 0.64,
              "y": 0.85
            },
            {
              "id": "jacket",
              "label": "jacket 2",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers"
            },
            {
              "from": "trousers",
              "to": "belt"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "under",
              "shirt"
            ]
          },
          "visited": [
            "socks"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 12,
        "variables": {
          "doing": "socks",
          "order": "socks"
        },
        "explanation": "Nothing blocks socks, so do it now. Order so far: socks.",
        "stats": {
          "comparisons": 1,
          "swaps": 0
        },
        "accent": "sorted"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "pivot"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "pivot"
            },
            {
              "id": "trousers",
              "label": "trousers 1",
              "x": 0.38,
              "y": 0.6
            },
            {
              "id": "belt",
              "label": "belt 2",
              "x": 0.64,
              "y": 0.4
            },
            {
              "id": "shoes",
              "label": "shoes 1",
              "x": 0.64,
              "y": 0.85,
              "role": "compare"
            },
            {
              "id": "jacket",
              "label": "jacket 2",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers"
            },
            {
              "from": "trousers",
              "to": "belt"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes",
              "role": "compare"
            },
            {
              "from": "shirt",
              "to": "belt"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "under",
              "shirt"
            ]
          },
          "visited": [
            "socks"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 16,
        "variables": {
          "unblocking": "shoes",
          "blockersLeft": 1
        },
        "explanation": "shoes is one blocker closer, but 1 still to go. Not ready yet.",
        "stats": {
          "comparisons": 1,
          "swaps": 1
        },
        "accent": "compare"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "pivot"
            },
            {
              "id": "trousers",
              "label": "trousers 1",
              "x": 0.38,
              "y": 0.6
            },
            {
              "id": "belt",
              "label": "belt 2",
              "x": 0.64,
              "y": 0.4
            },
            {
              "id": "shoes",
              "label": "shoes 1",
              "x": 0.64,
              "y": 0.85
            },
            {
              "id": "jacket",
              "label": "jacket 2",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers"
            },
            {
              "from": "trousers",
              "to": "belt"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "shirt"
            ]
          },
          "visited": [
            "socks",
            "under"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 12,
        "variables": {
          "doing": "under",
          "order": "socks → under"
        },
        "explanation": "Nothing blocks underwear, so do it now. Order so far: socks → under.",
        "stats": {
          "comparisons": 2,
          "swaps": 1
        },
        "accent": "sorted"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "pivot"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "compare"
            },
            {
              "id": "belt",
              "label": "belt 2",
              "x": 0.64,
              "y": 0.4
            },
            {
              "id": "shoes",
              "label": "shoes 1",
              "x": 0.64,
              "y": 0.85
            },
            {
              "id": "jacket",
              "label": "jacket 2",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers",
              "role": "compare"
            },
            {
              "from": "trousers",
              "to": "belt"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "shirt",
              "trousers"
            ]
          },
          "visited": [
            "socks",
            "under"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 16,
        "variables": {
          "unblocking": "trousers",
          "blockersLeft": 0
        },
        "explanation": "trousers was waiting on underwear. That was its last blocker — it's free to go, so it joins the queue.",
        "stats": {
          "comparisons": 2,
          "swaps": 2
        },
        "accent": "found"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "sorted"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "pivot"
            },
            {
              "id": "belt",
              "label": "belt 2",
              "x": 0.64,
              "y": 0.4
            },
            {
              "id": "shoes",
              "label": "shoes 1",
              "x": 0.64,
              "y": 0.85
            },
            {
              "id": "jacket",
              "label": "jacket 2",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers"
            },
            {
              "from": "trousers",
              "to": "belt"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "trousers"
            ]
          },
          "visited": [
            "socks",
            "under",
            "shirt"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 12,
        "variables": {
          "doing": "shirt",
          "order": "socks → under → shirt"
        },
        "explanation": "Nothing blocks shirt, so do it now. Order so far: socks → under → shirt.",
        "stats": {
          "comparisons": 3,
          "swaps": 2
        },
        "accent": "sorted"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "sorted"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "pivot"
            },
            {
              "id": "belt",
              "label": "belt 1",
              "x": 0.64,
              "y": 0.4,
              "role": "compare"
            },
            {
              "id": "shoes",
              "label": "shoes 1",
              "x": 0.64,
              "y": 0.85
            },
            {
              "id": "jacket",
              "label": "jacket 2",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers"
            },
            {
              "from": "trousers",
              "to": "belt"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt",
              "role": "compare"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "trousers"
            ]
          },
          "visited": [
            "socks",
            "under",
            "shirt"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 16,
        "variables": {
          "unblocking": "belt",
          "blockersLeft": 1
        },
        "explanation": "belt is one blocker closer, but 1 still to go. Not ready yet.",
        "stats": {
          "comparisons": 3,
          "swaps": 3
        },
        "accent": "compare"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "sorted"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "pivot"
            },
            {
              "id": "belt",
              "label": "belt 1",
              "x": 0.64,
              "y": 0.4
            },
            {
              "id": "shoes",
              "label": "shoes 1",
              "x": 0.64,
              "y": 0.85
            },
            {
              "id": "jacket",
              "label": "jacket 1",
              "x": 0.9,
              "y": 0.5,
              "role": "compare"
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers"
            },
            {
              "from": "trousers",
              "to": "belt"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt"
            },
            {
              "from": "shirt",
              "to": "jacket",
              "role": "compare"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "trousers"
            ]
          },
          "visited": [
            "socks",
            "under",
            "shirt"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 16,
        "variables": {
          "unblocking": "jacket",
          "blockersLeft": 1
        },
        "explanation": "jacket is one blocker closer, but 1 still to go. Not ready yet.",
        "stats": {
          "comparisons": 3,
          "swaps": 4
        },
        "accent": "compare"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "sorted"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "sorted"
            },
            {
              "id": "belt",
              "label": "belt 1",
              "x": 0.64,
              "y": 0.4
            },
            {
              "id": "shoes",
              "label": "shoes 1",
              "x": 0.64,
              "y": 0.85
            },
            {
              "id": "jacket",
              "label": "jacket 1",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "belt"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": []
          },
          "visited": [
            "socks",
            "under",
            "shirt",
            "trousers"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 12,
        "variables": {
          "doing": "trousers",
          "order": "socks → under → shirt → trousers"
        },
        "explanation": "Nothing blocks trousers, so do it now. Order so far: socks → under → shirt → trousers.",
        "stats": {
          "comparisons": 4,
          "swaps": 4
        },
        "accent": "sorted"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "sorted"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "sorted"
            },
            {
              "id": "belt",
              "label": "belt 0",
              "x": 0.64,
              "y": 0.4,
              "role": "compare"
            },
            {
              "id": "shoes",
              "label": "shoes 1",
              "x": 0.64,
              "y": 0.85
            },
            {
              "id": "jacket",
              "label": "jacket 1",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "belt",
              "role": "compare"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "belt"
            ]
          },
          "visited": [
            "socks",
            "under",
            "shirt",
            "trousers"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 16,
        "variables": {
          "unblocking": "belt",
          "blockersLeft": 0
        },
        "explanation": "belt was waiting on trousers. That was its last blocker — it's free to go, so it joins the queue.",
        "stats": {
          "comparisons": 4,
          "swaps": 5
        },
        "accent": "found"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "sorted"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "sorted"
            },
            {
              "id": "belt",
              "label": "belt 0",
              "x": 0.64,
              "y": 0.4,
              "role": "pivot"
            },
            {
              "id": "shoes",
              "label": "shoes 0",
              "x": 0.64,
              "y": 0.85,
              "role": "compare"
            },
            {
              "id": "jacket",
              "label": "jacket 1",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "belt"
            },
            {
              "from": "trousers",
              "to": "shoes",
              "role": "compare"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "belt",
              "shoes"
            ]
          },
          "visited": [
            "socks",
            "under",
            "shirt",
            "trousers"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 16,
        "variables": {
          "unblocking": "shoes",
          "blockersLeft": 0
        },
        "explanation": "shoes was waiting on trousers. That was its last blocker — it's free to go, so it joins the queue.",
        "stats": {
          "comparisons": 4,
          "swaps": 6
        },
        "accent": "found"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "sorted"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "sorted"
            },
            {
              "id": "belt",
              "label": "belt 0",
              "x": 0.64,
              "y": 0.4,
              "role": "sorted"
            },
            {
              "id": "shoes",
              "label": "shoes 0",
              "x": 0.64,
              "y": 0.85,
              "role": "pivot"
            },
            {
              "id": "jacket",
              "label": "jacket 1",
              "x": 0.9,
              "y": 0.5
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "belt",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt",
              "role": "sorted"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "shoes"
            ]
          },
          "visited": [
            "socks",
            "under",
            "shirt",
            "trousers",
            "belt"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 12,
        "variables": {
          "doing": "belt",
          "order": "socks → under → shirt → trousers → belt"
        },
        "explanation": "Nothing blocks belt, so do it now. Order so far: socks → under → shirt → trousers → belt.",
        "stats": {
          "comparisons": 5,
          "swaps": 6
        },
        "accent": "sorted"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "sorted"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "sorted"
            },
            {
              "id": "belt",
              "label": "belt 0",
              "x": 0.64,
              "y": 0.4,
              "role": "sorted"
            },
            {
              "id": "shoes",
              "label": "shoes 0",
              "x": 0.64,
              "y": 0.85,
              "role": "pivot"
            },
            {
              "id": "jacket",
              "label": "jacket 0",
              "x": 0.9,
              "y": 0.5,
              "role": "compare"
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "belt",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "shoes"
            },
            {
              "from": "socks",
              "to": "shoes"
            },
            {
              "from": "shirt",
              "to": "belt",
              "role": "sorted"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket",
              "role": "compare"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "shoes",
              "jacket"
            ]
          },
          "visited": [
            "socks",
            "under",
            "shirt",
            "trousers",
            "belt"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 16,
        "variables": {
          "unblocking": "jacket",
          "blockersLeft": 0
        },
        "explanation": "jacket was waiting on belt. That was its last blocker — it's free to go, so it joins the queue.",
        "stats": {
          "comparisons": 5,
          "swaps": 7
        },
        "accent": "found"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "sorted"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "sorted"
            },
            {
              "id": "belt",
              "label": "belt 0",
              "x": 0.64,
              "y": 0.4,
              "role": "sorted"
            },
            {
              "id": "shoes",
              "label": "shoes 0",
              "x": 0.64,
              "y": 0.85,
              "role": "sorted"
            },
            {
              "id": "jacket",
              "label": "jacket 0",
              "x": 0.9,
              "y": 0.5,
              "role": "pivot"
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "belt",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "shoes",
              "role": "sorted"
            },
            {
              "from": "socks",
              "to": "shoes",
              "role": "sorted"
            },
            {
              "from": "shirt",
              "to": "belt",
              "role": "sorted"
            },
            {
              "from": "shirt",
              "to": "jacket"
            },
            {
              "from": "belt",
              "to": "jacket"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": [
              "jacket"
            ]
          },
          "visited": [
            "socks",
            "under",
            "shirt",
            "trousers",
            "belt",
            "shoes"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 12,
        "variables": {
          "doing": "shoes",
          "order": "socks → under → shirt → trousers → belt → shoes"
        },
        "explanation": "Nothing blocks shoes, so do it now. Order so far: socks → under → shirt → trousers → belt → shoes.",
        "stats": {
          "comparisons": 6,
          "swaps": 7
        },
        "accent": "sorted"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "sorted"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "sorted"
            },
            {
              "id": "belt",
              "label": "belt 0",
              "x": 0.64,
              "y": 0.4,
              "role": "sorted"
            },
            {
              "id": "shoes",
              "label": "shoes 0",
              "x": 0.64,
              "y": 0.85,
              "role": "sorted"
            },
            {
              "id": "jacket",
              "label": "jacket 0",
              "x": 0.9,
              "y": 0.5,
              "role": "sorted"
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "belt",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "shoes",
              "role": "sorted"
            },
            {
              "from": "socks",
              "to": "shoes",
              "role": "sorted"
            },
            {
              "from": "shirt",
              "to": "belt",
              "role": "sorted"
            },
            {
              "from": "shirt",
              "to": "jacket",
              "role": "sorted"
            },
            {
              "from": "belt",
              "to": "jacket",
              "role": "sorted"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": []
          },
          "visited": [
            "socks",
            "under",
            "shirt",
            "trousers",
            "belt",
            "shoes",
            "jacket"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 12,
        "variables": {
          "doing": "jacket",
          "order": "socks → under → shirt → trousers → belt → shoes → jacket"
        },
        "explanation": "Nothing blocks jacket, so do it now. Order so far: socks → under → shirt → trousers → belt → shoes → jacket.",
        "stats": {
          "comparisons": 7,
          "swaps": 7
        },
        "accent": "sorted"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "socks",
              "label": "socks 0",
              "x": 0.12,
              "y": 0.22,
              "role": "sorted"
            },
            {
              "id": "under",
              "label": "underwear 0",
              "x": 0.12,
              "y": 0.72,
              "role": "sorted"
            },
            {
              "id": "shirt",
              "label": "shirt 0",
              "x": 0.38,
              "y": 0.12,
              "role": "sorted"
            },
            {
              "id": "trousers",
              "label": "trousers 0",
              "x": 0.38,
              "y": 0.6,
              "role": "sorted"
            },
            {
              "id": "belt",
              "label": "belt 0",
              "x": 0.64,
              "y": 0.4,
              "role": "sorted"
            },
            {
              "id": "shoes",
              "label": "shoes 0",
              "x": 0.64,
              "y": 0.85,
              "role": "sorted"
            },
            {
              "id": "jacket",
              "label": "jacket 0",
              "x": 0.9,
              "y": 0.5,
              "role": "sorted"
            }
          ],
          "edges": [
            {
              "from": "under",
              "to": "trousers",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "belt",
              "role": "sorted"
            },
            {
              "from": "trousers",
              "to": "shoes",
              "role": "sorted"
            },
            {
              "from": "socks",
              "to": "shoes",
              "role": "sorted"
            },
            {
              "from": "shirt",
              "to": "belt",
              "role": "sorted"
            },
            {
              "from": "shirt",
              "to": "jacket",
              "role": "sorted"
            },
            {
              "from": "belt",
              "to": "jacket",
              "role": "sorted"
            }
          ],
          "directed": true,
          "frontier": {
            "label": "queue",
            "ids": []
          },
          "visited": [
            "socks",
            "under",
            "shirt",
            "trousers",
            "belt",
            "shoes",
            "jacket"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 22,
        "variables": {
          "order": "socks → under → shirt → trousers → belt → shoes → jacket",
          "done": 7
        },
        "explanation": "A valid order: socks → underwear → shirt → trousers → belt → shoes → jacket. Every arrow points forwards in this list, which is exactly what a topological order means.",
        "stats": {
          "comparisons": 7,
          "swaps": 7
        },
        "accent": "sorted"
      }
    ]
  }
}