Topological Sort란?
- 순서가 정해져 있는 작업 처리해야 할 때 (선후 관계가 정해진 작업)
- Direct Graph의 모든 노드를 방향성에 거스르지 않고 순서대로 나열하는 것
- 조건 : DAG(Directed Acyclic Graph), 즉 방향이 존재하고 사이클이 없는 그래프여야 함.
Topological Sort 구현 방법
1. DFS 이용한 Topological Sort
- dfs를 그대로 적용하되 하나의 동작만 추가하면 끝
- 더 이상 이동할 노드 없으면 list에 추가 (재귀함수의 dfs에서 이웃 노드들 dfs호출한 뒤 for 문 뒤에 추가하면 됨)
import sys
from collections import deque
sys.setrecursionlimit(10 ** 6)
n, m = map(int, input().split())
edges = [tuple(map(int, input().split())) for _ in range(m)]
neighbor=[[] for _ in range(n+1)]
# 1. 인접 리스트 생성
for a,b in edges:
neighbor[a].append(b)
# 2. DFS 진행
visited=[0]*(n+1)
order =[]
def dfs(node):
visited[node]=1
for neigh in neighbor[node]:
if not visited[neigh]:
dfs(neigh)
order.append(node)
for i in range(1,n+1):
if not visited[i]:
dfs(i)
# 3. 생성한 list의 역순으로 출력
for i in order[::-1]:
print(i,end=" ")
2. In-Degree 이용한 Topological Sort
- In-degree : 현재 노드를 기준으로 몇 개의 노드가 들어오는지 (내 앞에 먼저 처리되어야 할 작업의 개수)
- in-degree가 0인 노드들을 전부 deque에 넣어주고 deque이 빌 때까지 진행
- deque에서 노드 하나 꺼내고 해당 노드의 이웃노드들을 순회하며 각 이웃노드들의 in-degree값을 1씩 빼준다
- 이 과정에서, 이웃 노드의 in-degree가 0이 된다면 deque에 넣어주기 (0이 됐다는 것은 사전에 처리해야 할 작업이 다 끝났다는 것)
import sys
from collections import deque
sys.setrecursionlimit(10 ** 6)
n, m = map(int, input().split())
edges = [tuple(map(int, input().split())) for _ in range(m)]
neighbor=[[] for _ in range(n+1)]
pq=deque()
indegree=[0]*(n+1)
# 1. 인접 리스트 생성 & indegree 계산
for a,b in edges:
neighbor[a].append(b)
indegree[b]+=1
# 2. indegree가 0인 노드들 deque에 추가
for i in range(1,n+1):
if indegree[i]==0:
pq.append(i)
# 3. deque에서 값 하나씩 꺼내서 업데이트
while pq:
node=pq.popleft()
print(node,end=" ") # deque에서 하나씩 꺼내며 바로 출력
# 이웃노드들의 indegree -1
for neigh in neighbor[node]:
indegree[neigh]-=1
if indegree[neigh]==0:
pq.append(neigh)
=> 만약 모든 노드를 방문하기 전에 deque(queue)가 비었다는 것은 사이클이 존재한다는 것
"즉, '위상정렬'을 통해 그래프에 사이클이 존재하는지 판단할 수 있습니다"
Topological Sort 이용해 그래프의 사이클 확인하기
[In-Degree 이용해 위상정렬을 할 경우]
1. deque에서 노드를 꺼내서 이웃노드를 살피는데 이웃노드의 in-degree가 0인 경우
2. 위상정렬을 모두 했는데(deque이 비어서 while 끝남) deque에 들어간 노드의 개수가 전체 노드의 개수보다 적을 때
from collections import deque
n, m = map(int, input().split())
edges = [tuple(map(int, input().split())) for _ in range(m)]
neighbor=[[] for _ in range(n+1) ]
indegree=[0]*(n+1)
cons=True # 사이클이 있는지 (위상정렬에 모순이 있는지) 확인하는 flag. 있으면 False로 변환
for a,b in edges:
neighbor[a].append(b)
indegree[b]+=1
pq=deque()
pq_cnt=0 # 모든 노드가 deque에 들어간 경험이 있는지 count
for i in range(1,n+1):
if indegree[i]==0:
pq.append(i)
pq_cnt+=1
while pq:
node=pq.popleft()
for neigh in neighbor[node]:
if indegree[neigh]==0: # 이웃노드에서 indegree를 1 빼야하는데 이미 0인 경우
cons=False
break
indegree[neigh]-=1
if indegree[neigh]==0:
pq.append(neigh)
pq_cnt+=1 # deque에 넣을 때 count+=1
if not cons: break
if pq_cnt!=n: cons=False # 모든 노드가 deque에 들어가지 않은 경우
if cons : print("Consistent")
else: print("Inconsistent")
사전 순대로 Topological Sort 하는 법
한 그래프에 대해 위상정렬을 할 때 하나의 방법만 존재하는 것은 아닙니다.

해당 예시만 봐도 1->2->3->4->5 도 가능하고, 1->3->2->4->5 도 가능합니다.
이런 경우 위상정렬을 '사전순대로 혹은 노드 번호가 작은수대로' 하기 위해선 어떻게 해야할까요?
- In-degree 방법에서 노드들을 넣고 빼준 deque을 대신해 priority queue를 사용하면 됩니다. priority queue는 넣은 순서를 유지하는 deque과 달리 자동으로 queue안에 있는 값을 정렬해줍니다.
import heapq #python에선 priority queue를 하기 위해 heapq 사용
n, m = map(int, input().split())
edges = [tuple(map(int, input().split())) for _ in range(m)]
adjacent=[[] for _ in range(n+1)]
indegree=[0]*(n+1)
for a,b in edges:
adjacent[a].append(b)
indegree[b]+=1
pq=[]
for i in range(1,n+1):
if indegree[i]==0:
heapq.heappush(pq, i)
while pq:
node=heapq.heappop(pq)
print(node,end=" ")
for neigh in adjacent[node]:
indegree[neigh]-=1
if indegree[neigh]==0:
heapq.heappush(pq,neigh)
Topological Sort의 시간복잡도 / 공간복잡도
1. 시간 복잡도 : O(V+E)
- V(노드 개수), E(엣지 개수).
- 진입차수(In-Degree) 계산 : O(E)
- Queue 초기화 : 모든 노드를 확인하며 진입차수가 0인 노드 찾기 O(V)
- 노드 방문 & In-Degree 계산 : O(V) , O(E) => O(V+E)
2. 공간 복잡도 : O(V+E)
- 인접 리스트 : O(V+E)
- In-degree 배열 : O(V)
- Queue : 최악의 경우 모든 정점이 한번에 존재 : O(V)
- 결과 리스트 : O(V)
=> O(V+E)
'CodingTest' 카테고리의 다른 글
| [코드트리 후기] 깃허브 잔디 심기 활용해서 독학으로 코딩테스트 루틴 만들기 (0) | 2026.06.01 |
|---|---|
| [코드트리 후기] 구현/조건문(겹치는 경우) 알고리즘 분석하기 (0) | 2026.05.25 |
| [코드트리 후기] 코딩테스트 준비, 갭체크부터 시작하기 (0) | 2026.05.18 |
| Kruskal & Prim (MST) 알고리즘 개념 정리 및 활용 방법 (python) (0) | 2026.04.29 |
| Union-Find (Disjoint) 개념 정리 및 활용 방법 (python) (0) | 2026.04.22 |