Amenable
Amenable's Blog
Amenable
  • λΆ„λ₯˜ 전체보기 (189)
    • πŸ“‚ JAVA (87)
      • μ΄νŽ™ν‹°λΈŒ μžλ°” (65)
      • μ£Όμš” κ°œλ… (22)
    • πŸ“‚ 개발 μ„œμ  (22)
      • μ‹€μš©μ£Όμ˜ ν”„λ‘œκ·Έλž˜λ¨Έ (1)
      • 객체지ν–₯의 사싀과 μ˜€ν•΄ (2)
      • 클린 μ½”λ“œ (8)
      • ν•¨κ»˜ 자라기 (1)
      • 그림으둜 λ°°μš°λŠ” HTTP&Network Basic (10)
    • πŸ“‚ λ°μ΄ν„°λ² μ΄μŠ€ (8)
      • κ°œλ… (8)
      • λ¬Έμ œν’€μ΄ (0)
    • πŸ“‚ λ„€νŠΈμ›Œν¬ (14)
      • κ°œλ… (6)
      • 성곡과 μ‹€νŒ¨λ₯Ό κ²°μ •ν•˜λŠ” 1%의 λ„€νŠΈμ›Œν¬ 원리 (8)
    • πŸ“‚ μŠ€ν”„λ§ (13)
      • κΈ°λ³Έ κ°œλ… (13)
    • πŸ“‚ WEB (5)
    • πŸ“‚ 자료ꡬ쑰 (12)
      • κ°œλ… (2)
      • μ •λ ¬ (8)
      • 트리 (2)
    • πŸ“‚ μ•Œκ³ λ¦¬μ¦˜ (10)
      • μ΅œμ†Œμ‹ μž₯트리 (2)
      • μ΅œλ‹¨ 경둜 (2)
      • λ¬Έμžμ—΄ (2)
      • ETC (4)
    • πŸ“‚ μ•Œκ³ λ¦¬μ¦˜_λ¬Έμ œν’€μ΄ (4)
      • BOJ_λ°±μ€€ (4)
    • πŸ“‚ ν”„λ‘œκ·Έλž˜λ° (3)
    • πŸ“‚ DevOps (2)
      • 배포 (2)
    • πŸ“‚ ν›„κΈ° (8)
      • μš°μ•„ν•œ ν…Œν¬μ½”μŠ€(ν”„λ¦¬μ½”μŠ€) (4)
      • 2023λ…„ (3)
      • 2024λ…„ (1)
    • πŸ“‚ 회고 (1)
      • 2023λ…„ (1)

λΈ”λ‘œκ·Έ 메뉴

  • πŸš€ GitHub

ν‹°μŠ€ν† λ¦¬

hELLO Β· Designed By μ •μƒμš°.
Amenable

Amenable's Blog

μœ„μƒ μ •λ ¬(Topology Sort)
πŸ“‚ 자료ꡬ쑰/μ •λ ¬

μœ„μƒ μ •λ ¬(Topology Sort)

2023. 3. 7. 23:49

1. μ •μ˜ 🧊

μœ„μƒ μ •λ ¬

  μœ„μƒ μ •λ ¬(Topology Sort)μ΄λž€ μˆœμ„œκ°€ μ •ν•΄μ Έ μžˆλŠ” μž‘업을 μ°¨λ‘€λŒ€λ‘œ μˆ˜ν–‰ν•  λ•Œ κ·Έ μˆœμ„œλ₯Ό κ²°μ •ν•΄ μ£ΌλŠ” μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€. 

  κ΅μœ‘κ³Όμ •μ˜ μ„ μˆ˜κ³Όλͺ©μ΄ μœ„μƒ 정렬을 μ„€λͺ…ν•˜λŠ” κ°€μž₯ μ μ ˆν•œ μ˜ˆμ‹œμ΄λ‹€. 컴퓨터 곡학을 μ „κ³΅ν•˜κ³  μžˆλŠ” 학생은 λ‹€μŒ 전곡과λͺ©(ex. μ•Œκ³ λ¦¬μ¦˜)을 λ“£κΈ° μœ„ν•΄μ„œλŠ” μ„ μˆ˜ κ³Όλͺ©(ex. 자료ꡬ쑰)을 ν•„μˆ˜μ μœΌλ‘œ λ“€μ–΄μ•Ό ν•œλ‹€. 

κΈ°μ΄ˆμ»΄ν“¨ν„°ν”„λ‘œκ·Έλž˜λ° → 자료ꡬ쑰 → μ•Œκ³ λ¦¬μ¦˜
자료ꡬ쑰 → λ…Όλ¦¬νšŒλ‘œλ°μ„€κ³„ → λ…Όλ¦¬νšŒλ‘œμ‹€ν—˜
μ•Œκ³ λ¦¬μ¦˜ → λ…Όλ¦¬νšŒλ‘œλ°μ„€κ³„ → λ…Όλ¦¬νšŒλ‘œμ‹€ν—˜

  λ˜ν•œ, μœ„μƒμ •λ ¬μ€ μœ„μ™€ 같이 μ—¬λŸ¬ 개의 κ²½λ‘œκ°€ μ‘΄μž¬ν•  수 μžˆλ‹€.

  λ§ˆμ§€λ§‰ νŠΉμ§•μœΌλ‘œλŠ” μœ„μƒ 정렬은 λΉ„μˆœν™˜ 유ν–₯ κ·Έλž˜ν”„(DAG - Directed Acyclic Graph)μ—λ§Œ 적용이 κ°€λŠ₯ν•˜λ‹€. 즉, 사이클이 λ°œμƒν•˜μ§€ μ•ŠλŠ” λ°©ν–₯ κ·Έλž˜ν”„μ—¬μ•Ό ν•œλ‹€.

 

2. λ™μž‘ 방식(BFS) πŸ₯€

  μœ„μƒ 정렬은 BFS와 DFSλ₯Ό 톡해 κ΅¬ν˜„ν•  수 μžˆλ‹€. μš°μ„  BFSλ₯Ό μ΄μš©ν•˜λŠ” 방법을 λ¨Όμ € μ•Œμ•„λ³΄μž.

  BFSλ₯Ό μ΄μš©ν•˜λŠ” 경우 μ§„μž… μ°¨μˆ˜μ™€ Queueλ₯Ό ν™œμš©ν•œλ‹€. λ™μž‘ 방식은 μ•„λž˜μ™€ κ°™λ‹€.

[λ™μž‘ 방식]

  1. μ§„μž… μ°¨μˆ˜κ°€ 0인 μ •점을 Queue에 λ„£λŠ”λ‹€.
  2. Queueμ—μ„œ μ›μ†Œμ— μ—°κ²°λœ 간선을 μ œκ±°ν•œλ‹€.
  3. 간선이 μ œκ±°κ°€ λœ ν›„ μ§„μž… μ°¨μˆ˜κ°€ 0이 λœ μ •점을 Queue에 λ„£λŠ”λ‹€.
  4. Queueκ°€ λΉŒ λ•ŒκΉŒμ§€ 2번과 3λ²ˆμ„ λ°˜λ³΅ν•œλ‹€.

  μž‘업이 λλ‚œ ν›„ λͺ¨λ“  정점을 λ°©λ¬Έν–ˆλ‹€λ©΄ μœ„μƒ 정렬이 κ°€λŠ₯ν•œ κ·Έλž˜ν”„μ΄κ³  κ·Έλ ‡μ§€ λͺ»ν•œ 상황은 사이클이 μ‘΄μž¬ν•˜λŠ” κ²½μš°μ΄λ‹€. μ•„λž˜μ˜ μœ„μƒ 정렬이 κ°€λŠ₯ν•œ μ˜ˆμ‹œμ™€ μœ„μƒ 정렬이 λΆˆκ°€λŠ₯ν•œ μ˜ˆμ‹œλ₯Ό 톡해 ν•œλ²ˆ 더 이해λ₯Ό μ‚΄νŽ΄λ³΄μž.

[μœ„μƒ 정렬이 κ°€λŠ₯ν•œ μ˜ˆμ‹œ]

정점 1 2 3 4 5 6
μ§„μž… 차수 0 0 1 2 1 2

 

정점 1 2 3 4 5 6
μ§„μž… 차수 λ°©λ¬Έ λ°©λ¬Έ 0 0 1 2

정점 1 2 3 4 5 6
μ§„μž… 차수 λ°©λ¬Έ λ°©λ¬Έ λ°©λ¬Έ λ°©λ¬Έ 0 1

정점 1 2 3 4 5 6
μ§„μž… 차수 λ°©λ¬Έ λ°©λ¬Έ λ°©λ¬Έ λ°©λ¬Έ λ°©λ¬Έ 0

정점 1 2 3 4 5 6
μ§„μž… 차수 λ°©λ¬Έ λ°©λ¬Έ λ°©λ¬Έ λ°©λ¬Έ λ°©λ¬Έ λ°©λ¬Έ

[μœ„μƒ 정렬이 λΆˆκ°€λŠ₯ν•œ μ˜ˆμ‹œ]

정점 1 2 3 4 5 6
μ§„μž… 차수 0 0 2 3 1 1

정점 1 2 3 4 5 6
μ§„μž… 차수 λ°©λ¬Έ λ°©λ¬Έ 1 1 1 1

  사이클이 있으면 아직 방문을 ν•˜μ§€ λͺ»ν–ˆμ§€λ§Œ μ •μ λ“€μ˜ μ§„μž… μ°¨μˆ˜κ°€ 0이 μ•„λ‹ˆλΌμ„œ 더 이상 방문을 ν•˜μ§€ λͺ»ν•˜λŠ” 상황이 λ°œμƒν•œλ‹€. 즉, λͺ¨λ“  정점을 λ°©λ¬Έν•˜μ§€ λͺ»ν•œ κ²½μš°λŠ” 사이클이 μžˆμ–΄μ„œ μœ„μƒ 정렬이 λΆˆκ°€λŠ₯ν•œ 상황이라고 ν•  수 μžˆλ‹€.

 

3. BFSλ₯Ό μ΄μš©ν•œ κ΅¬ν˜„ μ½”λ“œ (JAVA) 🍹

첫 μ€„μ—λŠ” μ •μ μ˜ κ°œμˆ˜μ™€ κ°„μ„ μ˜ 개수λ₯Ό λ°›μ•„μ˜¨λ‹€. 그리고 κ°„μ„ μ˜ 개수만큼 좜발 정점과 도착 정점듀을 보여쀀닀. μ•„λž˜λŠ” μœ„μ—μ„œ μ‚΄νŽ΄λ³Έ μ˜ˆμ‹œλ₯Ό μž…λ ₯으둜 λ‚˜νƒ€λ‚Έ 것이닀.

6 6
1 3
1 4
2 4
3 5
4 6
5 6
public class TopologySorting {
	static int N, M;
	static Node[] adjNode;
	static int[] inDegree;

	static class Node {
		int vertex;
		Node link;

		public Node(int vertex, Node link) {
			super();
			this.vertex = vertex;
			this.link = link;
		}
	}

	public static void main(String[] args) throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(in.readLine(), " ");
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());

		// 인접 리슀트
		adjNode = new Node[N + 1];
		// μ§„μž… 차수
		inDegree = new int[N + 1];
		int from, to;

		for(int i = 0; i < M; i++) {
			st = new StringTokenizer(in.readLine(), " ");
			from = Integer.parseInt(st.nextToken());
			to = Integer.parseInt(st.nextToken());
			// 인접 리슀트 μΆ”κ°€
			adjNode[from] = new Node(to, adjNode[from]);
			// μ§„μž… 차수 μΆ”κ°€
			inDegree[to]++;
		}

		// μœ„μƒ 정렬을 톡해 μ–»μ–΄μ§„ 경둜λ₯Ό
		// resultFromTopologySort에 μ €μž₯
		ArrayList<Integer> resultFromTopologySort = topologySortByBFS();
		
		if(resultFromTopologySort.size() == N) {
			System.out.println("μœ„μƒ μ •λ ¬ κ°€λŠ₯");
			for(Integer i : resultFromTopologySort) {
				System.out.print(i + " ");
			}
		}
		else {
			System.out.println("μœ„μƒ μ •λ ¬ λΆˆκ°€λŠ₯ (사이클 λ°œμƒ)");
		}
	}

	static ArrayList<Integer> topologySortByBFS(){
		Queue<Integer> queue = new ArrayDeque<>();
		// μ§„μž…μ°¨μˆ˜κ°€ 0인 정점 μΆ”κ°€
		for(int i = 1; i <= N; i++) {
			if(inDegree[i] == 0)
				queue.offer(i);
		}

		ArrayList<Integer> visitedNode = new ArrayList<>();
		while(!queue.isEmpty()) {
			int currentNode = queue.poll();
			visitedNode.add(currentNode);

			for(Node temp = adjNode[currentNode]; temp != null; temp = temp.link) {
				// μ—°κ²°λœ 간선을 μ œκ±°ν•΄μ£ΌλŠ” ν–‰μœ„
				inDegree[temp.vertex]--;
				
				// μ§„μž… μ°¨μˆ˜κ°€ 0이 된 경우
				if(inDegree[temp.vertex] == 0) {
					queue.offer(temp.vertex);
				}
			}
		}

		return visitedNode;
	}
}

 

4. λ™μž‘ 방식(DFS) 🍸

  DFSλ₯Ό μ΄μš©ν•˜λŠ” 경우 μ§„μž… μ°¨μˆ˜μ™€ λ°©λ¬Έ μ—¬λΆ€λ₯Ό ν™œμš©ν•œλ‹€. DFS의 경우 Stack을 μ΄μš©ν•˜λŠ” 방법도 μžˆλ‹€. Stack을 μ΄μš©ν•˜λ©΄ 경둜λ₯Ό μ‰½κ²Œ μ•Œ 수 μžˆμ§€λ§Œ 사이클 λ°œμƒ μ—¬λΆ€λ₯Ό μ•ŒκΈ° μ–΄λ ΅λ‹€. κ·Έλž˜μ„œ 이번 κΈ€μ—μ„œλŠ” μœ„μƒ 정렬인지 μ•„λ‹Œμ§€λ₯Ό μ‰½κ²Œ μ•Œμ•„λ³΄κΈ° μœ„ν•˜μ—¬ μ§„μž…μ°¨μˆ˜μ™€ λ°©λ¬Έμ—¬λΆ€λ₯Ό μ‚¬μš©ν•˜λŠ” 방식을 μ΄μš©ν•΄ 보자. (λ¬Όλ‘  이 방법도 경둜λ₯Ό 확인할 수 μžˆλ‹€.)

[λ™μž‘ λ°©μ‹]

  1. μ§„μž… μ°¨μˆ˜κ°€ 0인 μ •점을 λ¨Όμ € λ°©λ¬Έν•œλ‹€.
  2. DFS λ°©μ‹μ„ μ΄μš©ν•˜μ—¬ κ³„μ†ν•΄μ„œ λ‹€μŒ μ •μ μœΌλ‘œ μ§„ν–‰ν•œλ‹€.
    μ΄λ•Œ, λ°©λ¬Έ μ—¬λΆ€λ₯Ό ν‘œμ‹œν•΄ μ€€λ‹€.
  3. 더 μ΄μƒ μ§„ν–‰ν•  μˆ˜ μ—†μœΌλ©΄ λ°©λ¬Έ μ—¬λΆ€λ₯Ό ν•΄μ œν•˜λ©΄μ„œ λŒμ•„μ˜¨λ‹€.
  4. 아직 λ°©λ¬Έν•˜μ§€ μ•Šμ€ μ§„μž…μ°¨μˆ˜ 0인 μ •점듀을 κΈ°μ€€μœΌλ‘œ 1~3 κ³Όμ •을 λ°˜λ³΅ν•œλ‹€.

  λ§Œμ•½ 2번의 κ³Όμ •μ—μ„œ λ‹€μŒ 정점이 이미 λ°©λ¬Έν•œ 정점이라면 사이클이 λ°œμƒν•˜λŠ” κ·Έλž˜ν”„μ΄λ‹€. 즉, μœ„μƒ 정렬이 λΆˆκ°€λŠ₯ν•œ κ·Έλž˜ν”„μ΄λ‹€.

  μœ„μƒ 정렬이 κ°€λŠ₯ν•œ μ˜ˆμ‹œμ™€ μœ„μƒ 정렬이 λΆˆκ°€λŠ₯ν•œ μ˜ˆμ‹œλ₯Ό 톡해 λ‹€μ‹œ ν•œλ²ˆ μ•Œμ•„λ³΄μž. μ§„ν–‰ν•˜λ©΄μ„œ 방문체크λ₯Ό ν•΄μ£Όκ³  λŒμ•„μ˜€λ©΄μ„œ λ°©λ¬Έ 체크 ν•΄μ œν•˜λŠ” 것을 잘 κΈ°μ–΅ν•˜μž. 그러면 그림을 톡해 μ‰½κ²Œ 이해할 수 μžˆμ„ 거라고 μƒκ°ν•œλ‹€. 

[μœ„μƒ 정렬이 κ°€λŠ₯ν•œ μ˜ˆμ‹œ]

μœ„μƒ 정렬이 κ°€λŠ₯ν•œ κ·Έλž˜ν”„

1번 경둜 : 1 → 3 → 5 → 6

2번 경둜 : 1 → 4 → 6

3번 경둜 : 2 → 4 → 6

[μœ„μƒ 정렬이 λΆˆκ°€λŠ₯ν•œ μ˜ˆμ‹œ]

μœ„μƒ 정렬이 λΆˆκ°€λŠ₯ν•œ κ·Έλž˜ν”„

  사이클이 μ‘΄μž¬ν•˜λŠ” κ²½μš°λ„ μ‚΄νŽ΄λ³΄μž. μœ„μ—μ„œ μ–ΈκΈ‰ν•œ κ²ƒμ²˜λŸΌ λ°©λ¬Έ ν‘œμ‹œκ°€ λœ κ³³μ„ μž¬λ°©λ¬Έν•œλ‹€λ©΄ μ‚¬μ΄ν΄μ΄ λ°œμƒν•˜λŠ” κ²ƒμ΄λ‹€. 

 

5. DFSλ₯Ό μ΄μš©ν•œ κ΅¬ν˜„ μ½”λ“œ(JAVA) 🍷

  ν•΄λ‹Ή λ°©λ²•μ˜ μž…λ ₯ λ˜ν•œ μ •μ μ˜ κ°œμˆ˜μ™€ κ°„μ„ μ˜ 개수λ₯Ό λ°›μ•„μ˜€κ³ , κ°„μ„ μ˜ 개수만큼 좜발 정점과 도착 정점을 λ‚˜νƒ€λ‚Έλ‹€κ³  ν•˜μž. μ•„λž˜μ˜ μž…λ ₯은 μœ„μƒ 정렬이 λΆˆκ°€λŠ₯ν•œ κ·Έλž˜ν”„μ˜ μž…λ ₯이닀. (μœ„μƒ 정렬이 κ°€λŠ₯ν•œ κ·Έλž˜ν”„μ˜ μž…λ ₯은 BFSλ₯Ό μ΄μš©ν•œ κ΅¬ν˜„ μ½”λ“œμ—μ„œ μ°Έκ³ ν•  수 μžˆλ‹€.)

6 7
1 3
1 4
2 4
3 5
4 3
5 6
6 4
public class TopologySortingByDFS {
	static int N, M;
	static Node[] adjNode;
	static boolean[] visited;
	static boolean isCycle;
	static int[] inDegree;

	static class Node {
		int vertex;
		Node link;

		public Node(int vertex, Node link) {
			super();
			this.vertex = vertex;
			this.link = link;
		}
	}

	public static void main(String[] args) throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(in.readLine(), " ");
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		
		// 인접 리슀트
		adjNode = new Node[N + 1];
		// μ§„μž… 차수 - μΆœλ°œμ μ„ ν™•μΈν•˜κΈ° μœ„ν•œ 것
		inDegree = new int[N + 1];
		// λ°©λ¬Έ 체크 - 사이클 λ°œμƒ μ—¬λΆ€λ₯Ό ν™•μΈν•˜κΈ° μœ„ν•œ 것
		visited = new boolean[N + 1];
		int from, to;

		for(int i = 0; i < M; i++) {
			st = new StringTokenizer(in.readLine(), " ");
			from = Integer.parseInt(st.nextToken());
			to = Integer.parseInt(st.nextToken());
			// 인접 리슀트λ₯Ό λ§Œλ“€κΈ°
			adjNode[from] = new Node(to, adjNode[from]);
			// μ§„μž… 차수 μΆ”κ°€
			inDegree[to]++;
		}
		
		topologySortByDFS();

		if(isCycle) {
			System.out.println("μœ„μƒ μ •λ ¬ λΆˆκ°€λŠ₯ (사이클 λ°œμƒ)");
		}
		else {
			System.out.println("μœ„μƒ μ •λ ¬ κ°€λŠ₯");
		}
	}

	static void topologySortByDFS(){
		
		for(int i = 1; i <= N; i++) {
			if(inDegree[i] == 0) {
				visited[i] = true;
				dfs(i);
				visited[i] = false;
			}
		}
	}
	
	static void dfs(int current) {
		
		// λ§ˆμ§€λ§‰ 정점인 경우
		if(adjNode[current] == null) {
			return;
		}

		for(Node temp = adjNode[current]; temp != null; temp = temp.link) {
			// 사이클이 λ°œμƒν•˜λŠ” 경우
			if(visited[temp.vertex]) {
				isCycle = true;
				return;
			}
			visited[temp.vertex] = true;
			dfs(temp.vertex);
			visited[temp.vertex] = false;
		}
	}
}

 

6. μ‹œκ°„λ³΅μž‘λ„ πŸ§ƒ

  μœ„μƒ 정렬을 ν•  λ•Œ 'μ •μ μ˜ 개수 + κ°„μ„ μ˜ 개수'만큼 μ‹œκ°„μ΄ μ†Œμš”λœλ‹€. κ·ΈλŸ¬λ―€λ‘œ μœ„μƒ μ •λ ¬μ˜ μ‹œκ°„ λ³΅μž‘λ„λŠ” O(V  + E)이닀.

 

ν•΄λ‹Ή 글은
λ‚˜λ™λΉˆλ‹˜μ˜ μœ„μƒ μ •λ ¬(Topology Sort)
yoongrammerλ‹˜μ˜ μœ„μƒ μ •λ ¬(Topological sort) κ°œλ… 및 κ΅¬ν˜„
Topological Sorting using Kahn's Algorithm
을 μ°Έκ³ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

 

'πŸ“‚ 자료ꡬ쑰 > μ •λ ¬' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

퀡 μ •λ ¬ (Quick Sort)  (0) 2023.03.20
νž™ μ •λ ¬ (Heap Sort)  (0) 2023.03.12
병합 μ •λ ¬(Merge Sort)  (0) 2023.03.07
μ‚½μž… μ •λ ¬(Insertion Sort)  (0) 2023.03.06
선택 μ •λ ¬(Selection Sort)  (2) 2023.03.04
    'πŸ“‚ 자료ꡬ쑰/μ •λ ¬' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€
    • 퀡 μ •λ ¬ (Quick Sort)
    • νž™ μ •λ ¬ (Heap Sort)
    • 병합 μ •λ ¬(Merge Sort)
    • μ‚½μž… μ •λ ¬(Insertion Sort)
    Amenable
    Amenable
    CS, μžλ°”, 자료ꡬ쑰, μ•Œκ³ λ¦¬μ¦˜, μŠ€ν”„λ§, μŠ€ν”„λ§ λΆ€νŠΈμ— ν•΄λ‹Ήν•˜λŠ” κ°œλ°œμ— κ΄€ν•œ λ‚΄μš©μ„ κ³΅μœ ν•©λ‹ˆλ‹€.

    ν‹°μŠ€ν† λ¦¬νˆ΄λ°”