맨위로가기

위상정렬

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

위상 정렬은 방향 비순환 그래프(DAG)의 노드를 선형으로 정렬하는 알고리즘으로, 각 노드 간의 의존성 관계를 유지한다. 위상 정렬은 자기 자신을 가리키는 변이 없는 노드를 찾아 출력하고, 해당 노드와 연결된 변을 제거하는 과정을 반복하여 수행된다. 이 알고리즘은 작업 또는 업무의 순차적인 일정 관리, 명령어 스케줄링, 스프레드시트 수식 재계산, 논리 합성 등 다양한 분야에 활용된다. Kahn의 알고리즘과 깊이 우선 탐색(DFS) 기반 알고리즘이 대표적이며, 병렬 처리를 통해 성능을 향상시킬 수 있다. 또한, 위상 정렬은 최단 경로 계산에도 사용되며, 부분 순서 개념과 밀접한 관련이 있다.

더 읽어볼만한 페이지

  • 유향 그래프 - 강한 연결 요소
    강한 연결 요소는 유향 그래프에서 임의의 두 정점 간에 서로 도달 가능한 경로가 존재하는 부분 그래프를 의미하며, 깊이 우선 탐색 등 다양한 알고리즘으로 찾을 수 있고 그래프 이론과 알고리즘 설계에 중요한 개념이다.
  • 유향 그래프 - 유향 비순환 그래프
    유향 비순환 그래프(DAG)는 순환이 없는 유향 그래프로, 정점과 방향을 갖는 변으로 구성되어 도달 가능성 관계로 부분 순서를 표현하고, 위상 정렬을 통해 정점들을 선형으로 정렬할 수 있으며, 데이터 처리, 인과 구조 분석, 버전 관리 등 다양한 분야에서 활용된다.
  • 그래프 알고리즘 - 페이지랭크
    페이지랭크는 래리 페이지와 세르게이 브린이 개발한 알고리즘으로, 하이퍼링크로 연결된 문서 집합에서 웹 페이지의 상대적 중요도를 측정하며, 링크를 투표로 간주하여 페이지 순위를 재귀적으로 결정하고, 구글 검색 엔진의 초기 핵심 알고리즘으로 활용되었으며, 다양한 분야에서 활용된다.
  • 그래프 알고리즘 - 너비 우선 탐색
    너비 우선 탐색은 그래프 탐색 알고리즘으로, 큐 자료구조를 사용하여 시작 노드에서 인접한 노드들을 우선적으로 탐색하며, 가중치가 없는 그래프에서 최단 경로를 찾는 데 유용하고 다양한 분야에 활용된다.
  • 정렬 알고리즘 - 합병 정렬
    합병 정렬은 분할 정복 알고리즘을 사용하여 리스트를 재귀적으로 분할하고 정렬된 부분 리스트를 병합하는 비교 기반 정렬 알고리즘으로, O(n log n)의 시간 복잡도를 가지며 안정 정렬에 속하고 연결 리스트 정렬 및 외부 정렬에 유용하다.
  • 정렬 알고리즘 - 퀵 정렬
    퀵 정렬은 토니 호어가 개발한 분할 정복 방식의 효율적인 정렬 알고리즘으로, 피벗을 기준으로 리스트를 분할하여 정렬하는 과정을 재귀적으로 반복하며 다양한 최적화 기법과 변형이 존재한다.
위상정렬
개요
종류방향성 비순환 그래프(DAG)
시간 복잡도O(V + E)
알고리즘
방식깊이 우선 탐색
너비 우선 탐색
Kahn 알고리즘
활용
사용 예시작업 스케줄링
데이터 의존성 분석
소프트웨어 설치 및 빌드 순서 결정
순환 참조 탐지

2. 위상 정렬의 수행 과정

위상 정렬은 다음 단계를 반복하여 수행한다.

# 진입 차수가 0인 꼭짓점을 찾는다. 즉, 자신을 향하는 간선이 없는 꼭짓점을 선택한다.

# 선택된 꼭짓점을 결과 목록에 추가하고, 해당 꼭짓점과 그 꼭짓점에서 출발하는 모든 간선그래프에서 제거한다.

# 그래프에 아직 처리되지 않은 꼭짓점이 남아있다면 1단계로 돌아가 과정을 반복한다. 만약 처리할 꼭짓점이 더 이상 없다면, 정렬된 결과 목록을 반환하고 알고리즘을 종료한다.

3. 예시

위상 정렬의 대표적인 응용 사례는 일정 관리에서 작업(태스크)의 순서를 해당 의존성에 따라 정하는 것이다. 작업은 그래프의 정점(노드)으로 표현되며, 작업 ''x''가 완료되어야 작업 ''y''를 시작할 수 있는 경우(예: 옷을 세탁할 때, 세탁기가 먼저 작동을 마쳐야 건조기에 옷을 넣을 수 있는 경우) ''x''에서 ''y''로 향하는 간선이 존재한다고 본다. 이 경우 위상 정렬을 통해 작업을 수행해야 하는 순서를 알 수 있다.

이러한 위상 정렬 알고리즘과 밀접하게 관련된 응용은 1960년대 초 PERT(Program Evaluation and Review Technique) 기법의 맥락에서 프로젝트 관리 일정 관리를 위해 처음 연구되었다.[1] PERT 기법에서 그래프의 정점은 프로젝트의 중요한 단계(마일스톤)를 나타내고, 간선은 한 단계와 다른 단계 사이에서 수행되어야 하는 작업을 나타낸다. 위상 정렬은 프로젝트의 전체 일정을 결정하는 핵심 작업 순서인 임계 경로를 찾는 선형 시간 알고리즘의 기초를 형성한다.

컴퓨터 과학 분야에서도 위상 정렬은 다양하게 활용된다. 주요 예시는 다음과 같다.


  • -* 5, 7, 3, 11, 8, 2, 9, 10 (시각적으로 왼쪽에서 오른쪽, 위에서 아래로)
  • 3, 5, 7, 8, 11, 2, 9, 10 (가장 작은 번호의 사용 가능한 정점 우선)
  • 3, 5, 7, 8, 11, 2, 10, 9 (들어오는 이웃에 의한 사전식)
  • 5, 7, 3, 8, 11, 2, 10, 9 (가장 적은 수의 간선 우선)
  • 7, 5, 11, 3, 10, 8, 9, 2 (가장 큰 번호의 사용 가능한 정점 우선)
  • 5, 7, 11, 2, 3, 8, 9, 10 (위에서 아래로, 왼쪽에서 오른쪽으로 시도)
  • 3, 7, 8, 5, 11, 10, 2, 9 (임의)]]

4. 알고리즘

위상 정렬에 사용되는 일반적인 알고리즘은 그래프의 노드(정점) 수와 간선(엣지) 수의 합에 비례하는 선형 시간 복잡도, 즉 O(|V| + |E|)를 가진다.

4. 1. Kahn의 알고리즘

Kuhn의 알고리즘과 혼동하지 않도록 주의해야 한다.

Kahn의 알고리즘은 1962년 Arthur B. Kahn이 처음 제안한 위상 정렬 알고리즘 중 하나이다.[2] 이 알고리즘은 최종적으로 정렬될 순서대로 정점을 선택해 나가는 방식으로 작동한다.

먼저, 그래프에서 들어오는 간선(incoming edge)이 전혀 없는 '시작 노드'들을 찾아서 집합 S에 넣는다. 주어진 그래프가 사이클이 없는 방향 그래프(DAG)라면 이러한 시작 노드는 반드시 하나 이상 존재한다. 그 다음 과정은 아래 의사 코드와 같다.

```wiki

L ← 정렬된 결과를 저장할 빈 리스트

S ← 들어오는 간선이 없는 모든 노드의 집합

'''while''' S가 비어 있지 않은 동안 반복:

S에서 노드 n을 하나 꺼낸다 (어떤 것을 꺼내는지는 구현에 따라 다름)

n을 L에 추가한다

'''for each''' n에서 나가는 간선 e (n → m) 각각에 대해 다음을 수행:

그래프에서 간선 e를 제거한다

'''if''' 노드 m으로 들어오는 다른 간선이 없다면:

m을 S에 추가한다

'''if''' 그래프에 간선이 남아 있다면:

'''return''' 오류 (그래프에 사이클이 존재함)

'''else''':

'''return''' L (위상 정렬된 순서)

```

만약 주어진 그래프가 DAG라면, 알고리즘이 종료된 후 리스트 L은 가능한 위상 정렬 결과 중 하나를 담게 된다. 위상 정렬 결과는 유일하지 않을 수 있다. 만약 알고리즘 종료 후에도 그래프에 간선이 남아 있다면, 이는 그래프 내에 사이클이 존재한다는 의미이며, 이 경우 위상 정렬은 불가능하다.

결과 정렬의 비고유성을 반영하여, 노드를 임시로 저장하는 구조 S는 단순한 집합뿐만 아니라 큐나 스택으로 구현할 수도 있다. S에서 노드를 어떤 순서로 꺼내는지에 따라 다른 위상 정렬 결과를 얻을 수 있다. 예를 들어, 큐를 사용하면 너비 우선 탐색(BFS)과 유사하게 동작하며, 스택을 사용하면 깊이 우선 탐색(DFS)과 유사하게 동작한다.

사전식으로 동률을 처리하는 Kahn 알고리즘의 변형은 병렬 스케줄링 및 계층적 그래프 그리기를 위한 Coffman–Graham 알고리즘의 핵심 요소로 사용된다.

이 알고리즘의 시간 복잡도는 일반적으로 그래프의 노드 수(|V|)와 간선 수(|E|)에 대해 선형적인 O(|V|+|E|)이다. 각 노드와 간선을 한 번씩 방문하고 처리하기 때문이다.

4. 2. 깊이 우선 탐색(DFS) 기반 알고리즘

위상 정렬을 수행하는 또 다른 방법은 깊이 우선 탐색(DFS)을 이용하는 것이다. 이 알고리즘은 그래프의 각 노드를 임의의 순서로 방문하며 깊이 우선 탐색을 수행한다. 특정 노드에서 출발한 탐색은 아직 방문하지 않은 이웃 노드로 계속 진행하며, 더 이상 방문할 노드가 없거나 이미 현재 탐색 경로에서 방문 중인 노드(순환 감지) 또는 탐색이 완료된 노드에 도달하면 종료된다. 한 노드에 대한 탐색이 완전히 종료되면, 해당 노드를 결과 리스트 `L`의 맨 앞에 추가한다.

이 방식의 핵심 원리는 어떤 노드 ''n''이 리스트 `L`에 추가되는 시점에는, ''n''으로부터 시작해서 도달할 수 있는 모든 후속 노드들(즉, ''n''에 의존하는 노드들)의 탐색이 이미 종료되어 `L`에 먼저 추가되어 있다는 점이다. 이는 깊이 우선 탐색의 재귀적 특성 덕분에 자연스럽게 만족된다.

다음은 순환(cycle) 감지 기능이 포함된 깊이 우선 탐색 기반 위상 정렬 알고리즘의 의사 코드이다. 이 알고리즘은 그래프가 방향 비순환 그래프(DAG)가 아닐 경우, 즉 순환이 존재하면 이를 감지하고 중단할 수 있다.



L ← 위상 정렬된 결과가 들어갈 빈 연결 리스트

nodes ← 그래프의 모든 노드 집합

node_status ← 각 노드의 상태를 저장하는 맵 (초기 상태: "미방문")

// 모든 노드에 대해 방문 시도

for each node n in nodes do

if node_status[n] == "미방문" then

visit(n)

// 재귀적 방문 함수

function visit(node n)

// "방문 중" 표시는 현재 탐색 경로상에 있음을 의미.

// 이 상태의 노드를 다시 만나면 순환이 존재한다는 뜻이다.

if node_status[n] == "방문 중" then

// 순환 감지: DAG가 아님

stop("오류: 그래프에 순환이 존재합니다.")

// "탐색 완료" 상태가 아니면 탐색 진행

if node_status[n] == "미방문" then

node_status[n] = "방문 중" // 현재 탐색 경로에 포함됨을 표시

// n에서 나가는 모든 간선 (n, m)에 대해 재귀 호출

for each edge (n, m) do

visit(m)

// n과 관련된 모든 하위 탐색이 끝났으므로 상태 변경

node_status[n] = "탐색 완료" // 탐색이 완전히 종료됨을 표시

// 결과 리스트 L의 맨 앞에 n을 추가

n을 L의 맨 앞에 추가한다.



이 알고리즘은 각 노드와 간선을 최대 한 번씩만 방문하므로, 그래프의 노드 수를 V, 간선 수를 E라고 할 때 시간 복잡도는 O(V + E)로 선형 시간에 수행된다.

이 깊이 우선 탐색 기반 알고리즘은 『알고리즘 개론』(Cormen 외 공저)에서 설명되었으며[3], 타잔(Tarjan)이 1976년에 처음 발표한 것으로 알려져 있다.[4]

4. 3. 병렬 알고리즘

병렬 랜덤 접근 기계(PRAM) 모델에서는, 다수의 프로세서를 사용하여 위상 정렬을 O(\log^2 n) 시간에 수행할 수 있다. 이는 위상 정렬 문제가 복잡도 클래스 '''NC2'''에 속함을 의미한다.[6] 한 가지 방법은 주어진 그래프의 인접 행렬을 min-plus 행렬 곱셈을 사용하여 최소화 대신 최대화를 수행하면서 로그적으로 여러 번 반복하여 제곱하는 것이다. 결과 행렬은 그래프의 각 정점까지의 최장 경로 거리를 나타낸다. 계산된 최장 경로의 길이를 기준으로 정점들을 정렬하면 위상 정렬 순서를 얻을 수 있다.

분산 메모리 환경에서는 Kahn의 알고리즘을 병렬화하여 위상 정렬을 수행할 수 있다. 이 방식은 방향 비순환 그래프(DAG) G = (V, E)를 여러 처리 요소(PE, Processing Element)에 분산시킨다. 각 PE i는 자신이 담당하는 정점 중 진입 차수가 0인 정점들의 로컬 목록 Q_i를 관리한다.

알고리즘은 여러 단계를 반복하며 진행된다. 각 단계 k에서는 모든 PE에 있는 진입 차수 0인 정점들(Q_i^k)을 찾는다. 이 정점들에 전역적인 순서(위상 정렬 순서)를 부여하기 위해, 각 PE가 가진 진입 차수 0인 정점 수에 대해 접두사 합을 계산한다. 이를 통해 각 정점에 고유한 위상 순서 인덱스를 할당할 수 있다.

두 개의 처리 요소를 가진 방향 비순환 그래프(DAG)에서 병렬 위상 정렬 알고리즘의 실행 예시.


순서가 부여된 정점들은 위상 정렬 결과에 추가되고 그래프에서 제거된다. 이때 해당 정점에서 나가는 간선 (u, v)들도 함께 제거되는데, 만약 간선의 도착점 v가 다른 PE l (j \neq l)에 있다면, 해당 PE l로 간선 제거에 대한 메시지 (u, v)를 보낸다. 메시지를 받은 PE는 도착점 v의 진입 차수를 갱신한다. 만약 v의 진입 차수가 0이 되면, 다음 단계 k+1에서 처리될 정점 목록 Q_j^{k+1}에 추가된다.

이 과정은 그래프 내 가장 긴 경로의 길이 D에 1을 더한 횟수(D+1회)만큼 반복되며, 더 이상 진입 차수가 0인 정점이 없을 때(\sum_{i=0}^{p-1} |Q_i^{D+1}| = 0) 종료된다. 이 알고리즘의 실행 시간은 통신 비용에 크게 영향을 받는다. 동시 읽기, 동시 쓰기가 가능한 CRCW PRAM 모델을 가정할 때, p개의 프로세서를 사용한 실행 시간은 \mathcal{O} \left(\frac{m + n}{p} + D (\Delta + \log p)\right)이다. 여기서 n은 정점 수, m은 간선 수, D는 그래프 내 최장 경로 길이, \Delta는 최대 차수이다.

5. 최단 경로 찾기에서의 적용

위상 정렬은 가중치가 있는 방향 비순환 그래프(DAG)를 통해 최단 경로를 빠르게 계산하는 데 사용될 수 있다. 그래프의 정점 목록을 위상 정렬 순서대로 V라고 할 때, 시작 정점 s에서 다른 모든 정점까지의 최단 경로는 다음 알고리즘을 통해 계산할 수 있다.

1. 정점 개수(|V|)와 같은 길이의 배열 d를 준비한다. 이 배열은 시작 정점 s로부터의 최단 경로 거리를 저장한다. d[s] = 0으로 초기화하고, 나머지 모든 정점 u에 대해서는 d[u] = \infty로 설정한다.

2. 정점 개수와 같은 길이의 배열 p를 준비하고, 모든 요소를 `nil`로 초기화한다. 각 p[u]는 시작 정점 s에서 정점 u까지의 최단 경로에서 u의 직전 정점(선행자)을 저장한다.

3. 시작 정점 s부터 시작하여, 위상 정렬 순서 V에 따라 각 정점 u를 순회한다.

4. 현재 정점 u에서 나가는 간선이 연결하는 각 정점 v에 대해 다음을 수행한다.


  • 간선 (u, v)의 가중치를 w라고 한다.
  • 간선 완화(edge relaxation): 만약 d[v] > d[u] + w 이면, 더 짧은 경로를 찾았으므로 d[v]p[v]를 갱신한다.
  • d[v] \leftarrow d[u] + w
  • p[v] \leftarrow u


이 알고리즘은 n개의 정점과 m개의 간선을 가진 그래프에서 \Theta(n + m)의 시간 복잡도, 즉 선형 시간에 실행된다.

6. 유일성

만약 위상 정렬 결과에서 인접한 모든 정점(노드) 쌍이 간선으로 연결되어 있다면, 이 간선들은 원래의 방향 비순환 그래프(DAG)에서 해밀턴 경로를 형성한다.

해밀턴 경로가 존재할 경우, 위상 정렬 결과는 유일하다. 다른 어떤 순서도 해밀턴 경로의 간선 순서를 만족하지 않기 때문이다. 반대로, 위상 정렬 결과가 해밀턴 경로를 형성하지 않는다면, 해당 DAG는 두 개 이상의 유효한 위상 정렬 결과를 가진다. 이는 정렬된 순서에서 서로 간선으로 연결되지 않은 인접한 정점 쌍이 존재한다는 의미이며, 이 두 정점의 순서를 바꾸어도 여전히 유효한 위상 정렬이 되기 때문이다.

따라서 DAG에서 위상 정렬 결과가 유일한지, 즉 해밀턴 경로가 존재하는지는 선형 시간 안에 확인할 수 있다. 이는 일반적인 유향 그래프에서 해밀턴 경로를 찾는 문제가 NP-난해인 것과 대조적이다.[5]

7. 부분 순서와의 관계

위상 정렬은 수학의 부분 순서(partial order) 및 선형 확장(linear extension) 개념과 깊은 관련이 있다.

부분 순서 집합은 특정 관계 "≤"를 만족하는 객체들의 모임이다. 이 관계는 다음 세 가지 공리를 만족해야 한다.


  • 반사성: 모든 객체 ''x''에 대해 ''x'' ≤ ''x''이다.
  • 반대칭성: 만약 ''x'' ≤ ''y''이고 ''y'' ≤ ''x''이면, ''x'' = ''y''이다.
  • 추이성: 만약 ''x'' ≤ ''y''이고 ''y'' ≤ ''z''이면, ''x'' ≤ ''z''이다.


전순서(total order)는 부분 순서의 특별한 경우로, 집합 안의 임의의 두 객체 ''x''와 ''y''에 대해 ''x'' ≤ ''y'' 또는 ''y'' ≤ ''x'' 둘 중 하나가 반드시 성립하는 경우를 말한다. 컴퓨터 과학에서 비교 정렬 알고리즘을 수행할 때 사용하는 비교 연산자가 바로 이 전순서에 해당한다. 유한 집합의 경우, 전순서는 객체들을 일렬로 나열한 순서로 볼 수 있으며, "≤" 관계는 순서상 앞에 오는 객체가 뒤에 오는 객체보다 작거나 같다는 것을 의미한다. 비교 정렬 알고리즘은 이러한 전순서를 실제 순서열로 만드는 데 사용될 수 있다.

부분 순서의 선형 확장은 원래의 부분 순서 관계를 보존하면서 모든 객체 쌍에 대해 순서를 정의하는 전순서를 의미한다. 즉, 원래 부분 순서에서 ''x'' ≤ ''y''였다면, 선형 확장에서도 반드시 ''x'' ≤ ''y'' 관계가 유지되어야 한다.

방향성 비순환 그래프(DAG)와 부분 순서 사이에는 밀접한 관계가 있다. DAG의 정점들을 객체 집합으로 보고, 한 정점 ''x''에서 다른 정점 ''y''로 가는 유향 경로가 존재할 때, 즉 ''y''가 ''x''로부터 도달 가능할 때 ''x'' ≤ ''y''라고 정의하면, 이는 부분 순서를 형성한다. 이러한 정의 하에서, DAG의 위상 정렬 결과는 바로 이 부분 순서의 선형 확장과 동일하다.

반대로, 어떤 부분 순서가 주어졌을 때, 이를 나타내는 DAG를 만들 수도 있다. 한 가지 방법은 부분 순서 집합의 각 객체에 해당하는 정점을 만들고, ''x'' ≤ ''y''인 모든 객체 쌍 (''x'', ''y'')에 대해 ''x''에서 ''y''로 가는 간선 ''xy''를 추가하는 것이다. 다른 방법으로는 부분 순서의 추이 감소(transitive reduction)를 이용하여 DAG를 만드는 것이 있다. 추이 감소를 이용하면 일반적으로 더 적은 수의 간선을 가진 DAG가 만들어지지만, 두 정점 간의 도달 가능성 관계는 원래의 부분 순서와 동일하게 유지된다. 이렇게 부분 순서를 DAG로 표현하면, 위상 정렬 알고리즘을 사용하여 해당 부분 순서의 선형 확장을 구할 수 있다.

8. 스케줄링 최적화와의 관계

정의에 따르면, 선행 제약 조건 그래프를 포함하는 스케줄링 문제의 해는 유효한 위상 정렬 결과가 된다. 이는 사용할 수 있는 기계 수와 관계없이 성립한다.

그러나 위상 정렬 자체만으로는 스케줄링 최적화 문제를 해결하기에 충분하지 않다. 예를 들어, 각 작업의 처리 시간까지 고려하여 전체 완료 시간을 최소화하는 것과 같은 최적화 목표를 달성하기 위해서는 추가적인 알고리즘이 필요하다.

Hu의 알고리즘은 선행 제약 조건과 처리 시간을 모두 고려하는 스케줄링 문제를 해결하기 위해 사용되는 대표적인 방법 중 하나이다. 이 알고리즘의 목표는 모든 작업 중에서 가장 늦게 끝나는 작업의 완료 시간(makespan)을 최소화하는 것이다. 위상 정렬과 마찬가지로 Hu의 알고리즘으로 구한 해가 유일하지 않을 수 있으며, DFS를 이용하여 가장 긴 경로 길이를 찾고 작업을 할당하는 방식으로 문제를 해결할 수도 있다.

참조

[1] 간행물 Automatic machine methods of testing PERT networks for consistency U. S. Naval Weapons Laboratory
[2] 논문 Topological sorting of large networks
[3] 서적 アルゴリズムイントロダクション 近代科学社 2013-12-17
[4] 논문 Edge-disjoint spanning trees and depth-first search
[5] 논문 Proc. 17th International Conference of the Chilean Computer Science Society (SCCC '97)
[6] 간행물 A Taxonomy of Problems with Fast Parallel Algorithms



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com