위상 정렬
- 유향 그래프의 정점들을 변의 방향을 거스르지 않도록 나열하는 것
- 순서가 정해져 있는 작업들을 차례대로 수행해야 할 때, 그 순서를 결정해주는 알고리즘
- 선수과목 구조를 예로 들 수 있음 -> 선후 관계가 정의된 상황
- 유향 그래프의 구조에 따라 여러 종류의 순서가 나올 수 있음
- 그래프 내에서 순환이 존재하면 안됨
- 비순환 유향 그래프에서 사용 가능
구현
- 진입 차수가 0인 정점(시작 포함)을 큐에 모드 넣는다.
- 큐에서 진입 차수가 0인 정점을 꺼내어 자신과 인접한 정점의 간선을 제거한다.
- 간선 제거 후 진입 차수가 0이 된 정점을 큐에 넣는다.
- 큐가 공백이 될 때까지 2 - 3 작업 반복
- 모든 노드가 다 처리되었다면 위상 정렬 완성
- 모든 노드가 처리되지 않았다면 사이클 발생
package algo0828;
import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;
public class TopologicalSorting {
static int V, E;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
for (int t = 1; t <= 10; t++) {
sb.append("#").append(t).append(" ");
StringTokenizer st = new StringTokenizer(br.readLine());
V = Integer.parseInt(st.nextToken());
E = Integer.parseInt(st.nextToken());
int[] edgeCount = new int[V + 1];
ArrayList<ArrayList<Integer>> graph = new ArrayList<>();
for (int i = 0; i < V + 1; i++) {
graph.add(new ArrayList<>());
}
st = new StringTokenizer(br.readLine());
for (int i = 0; i < E; i++) {
int to = Integer.parseInt(st.nextToken());
int from = Integer.parseInt(st.nextToken());
graph.get(to).add(from);
edgeCount[from]++;
}
Queue<Integer> q = new LinkedList<>();
for(int i = 1; i < edgeCount.length; i++) {
if(edgeCount[i] == 0) {
q.offer(i);
}
}
while(!q.isEmpty()) {
int nodeNo = q.poll();
sb.append(nodeNo).append(" ");
List<Integer> list = graph.get(nodeNo);
for(int i = 0; i < list.size(); i++) {
edgeCount[list.get(i)]--;
if(edgeCount[list.get(i)] == 0) {
q.offer(list.get(i));
}
}
}
sb.append("\n");
}
System.out.println(sb);
}
}
ref : https://codingnojam.tistory.com/66