"양말 전에 신발을 못 신어. 위상 정렬은 'X 가 Y 보다 먼저' 규칙 뭉치를 주면, 모든 걸 할 유효한 순서를 건네는 — 또는 규칙이 자기모순이라고 알려주는 — 알고리즘이야."
문제
엣지 X→Y 가 "X 가 Y 보다 먼저" 를 뜻하는 방향 비순환 그래프 (DAG) 가 주어지면, 위상 정렬이 모든 노드를, 각 노드가 모든 선행조건 뒤에 나타나는 선형 순서로 만들어. 천 개 일상 시스템 뒤의 수학이야: 빌드 도구가 의존성 순으로 파일 컴파일, 패키지 매니저가 의존성 먼저 설치, 강의 선수과목, 작업 스케줄러, 스프레드시트 셀이 맞는 순서로 재계산, Python 이 네 모듈 import 하는 순서까지. 질문이 "이 상호의존하는 것들을 할 유효한 순서가 뭐야?" 면, 위상 정렬이야.
Kahn 알고리즘: 준비된 것부터 벗겨내
가장 직관적인 방법은 진입 차수 (in-degree) — 각 노드가 아직 안 채운 선행조건이 몇 개냐 — 로 작동해. 반복해서: 남은 선행조건이 0 인 (실행 준비된) 노드를 아무거나 가져와, 출력하고, 그 나가는 엣지를 제거해 (이웃의 진입 차수를 줄여, 걔네도 준비되게 할 수도). 준비된 노드를 담는 데 큐를 써. 다 출력될 때까지 계속. BFS 향이야: 현재 할 수 있는 작업의 frontier 를 처리하면 다음 frontier 가 열려. O(V + E).
대안은 DFS 후위: 그래프를 DFS 하고, 각 노드가 끝날 때 (모든 후손 완료), 답 앞에 붙여. 후위를 뒤집으면 유효한 위상 순서야. 둘 다 표준; Kahn 이 종종 추론하기 쉬워, '선행조건 0 = 준비됨' 이 직관에 깔끔히 매핑되니까.
보너스: 순환 검출
위상 정렬은 DAG — 순환 없는 그래프 — 에서만 작동해. 그리고 그게 위반되면 알려줘: Kahn 알고리즘에서, 전부 출력하기 전에 진입차수 0 노드가 떨어지면, 남은 노드가 순환을 이뤄 (상호 의존: A 가 B 필요, B 가 A 필요 — 어느 것도 절대 '준비' 못 돼). 진짜 쓸모 있는 진단이야: "순환 의존성 검출됨" 을 보고하는 빌드 시스템이 실패한 위상 정렬이야. 그래서 알고리즘은 할 수 있는 걸 순서 매길 뿐 아니라 — 유효한 순서가 애초에 존재하는지 증명해.