Search
🏫

[알고리즘] 6. 그래프 (1) - 기본 개념/순회

Tags
CS
Algorithm
Last edited time
2024/12/27 06:43
2 more properties
Search
[알고리즘] 14. 탐색 알고리즘 요약
CS
Algorithm
2025/01/05 2:47
[알고리즘] 14. 탐색 알고리즘 요약
CS
Algorithm
2025/01/05 2:47

1. 기본 개념

1.1. 그래프의 정의

그래프 G → G = (V, E)
V: 정점(Vertex)의 집합
E: 간선(Edge)의 집합
그래프의 종류
1.
무방향 그래프 (Undirected Graph): 간선의 방향이 없음
2.
방향 그래프 (Directed Graph): 간선의 방향이 있음
3.
가중 그래프 (Weighted Graph): 간선에 가중치가 부여됨

1.2. 주요 용어

인접(Adjacent): 두 정점이 간선으로 연결되어 있을 때
부수(Incident): 정점과 간선이 연결되어 있을 때
부분 그래프(Subgraph): 주어진 그래프의 부분 집합으로 구성된 그래프
경로(Path): 정점과 간선의 연속적인 열
경로의 길이: 경로에 포함된 간선의 수
차수(Degree)
진입 차수(In-degree): 방향 그래프에서 정점으로 들어오는 간선의 수
진출 차수(Out-degree): 방향 그래프에서 정점에서 나가는 간선의 수
단순 경로(Simple Path): 중복 간선 없이 정점을 방문하는 경로
사이클(Cycle): 시작 정점과 종료 정점이 동일한 경로
루프(Loop): 하나의 정점에서 시작하여 다시 자기 자신으로 돌아오는 간선
연결성(Connectedness)
강하게 연결(Strongly Connected): 방향 그래프에서 모든 정점 간 양방향 경로 존재
약하게 연결(Weakly Connected): 방향 무시 시 연결된 상태

1.3. 그래프의 구현

인접 행렬 (Adjacency Matrix)
정점 수 의 제곱 크기 행렬로 표현 |V| * |V|
조밀 그래프 (Dense Graph)에 적합
인접 리스트 (Adjacency List)
각 정점마다 연결 리스트로 이웃한 정점을 기록.
성긴 그래프 (Sparse Graph)에 적합

2. 그래프 순회

그래프의 모든 정점을 체계적으로 한 번씩 방문하는 방법

2.1. 깊이 우선 탐색 (DFS)

동작 방식
정점 하나를 선택 후 가능한 한 깊게 탐색
더 이상 갈 곳이 없으면 뒤로 돌아가 탐색하지 않은 경로를 계속 진행
시간 복잡도
인접 리스트 O(|V| + |E|)
인접 행렬 O(|V|^2)
스택을 활용한 구현
DepthFirstSearch (G, s) { // G: 입력 그래프, s: 시작 정점 Push(Stack, s); while (Stack != NULL) { c = Stack의 top에 있는 정점; c.visited = TRUE; 정점 c를 방문 정점으로 출력; do { for (v ← c의 모든 인접한 정점) { if (v.visited == FALSE) Push(Stack, v)while문으로 이동; } c = Pop(Stack); } while (Stack != NULL); } }
C
복사
def DepthFirstSearch(G, s): # G: 입력 그래프, s: 시작 정점 Stack = [] Stack.append(s) # 시작 정점을 스택에 삽입 while Stack: # 스택이 비어 있지 않은 동안 반복 c = Stack[-1] # 스택의 top에 있는 정점을 가져옴 c.visited = True # 정점 c를 방문으로 표시 print(f"정점 {c} 방문") # 정점 c를 방문 정점으로 출력 has_unvisited = False # 방문하지 않은 정점 여부를 확인 for v in G.adjacent(c): # c의 모든 인접한 정점을 확인 if not v.visited: Stack.append(v) # 방문하지 않은 정점을 스택에 삽입 has_unvisited = True break # 새로운 정점을 방문했으므로 반복 종료 if not has_unvisited: Stack.pop() # 방문할 정점이 없으면 스택에서 제거
Python
복사
재귀를 활용한 구현
DFS_recursion (G, current) { current.visited = TRUE; 방문 정점으로 current 출력; for (next ← current의 모든 인접한 정점) { if (next.visited == FALSE) DFS_recursion(G, next); } }
C
복사
def DFS_recursion(G, current): current.visited = True # 현재 정점을 방문으로 표시 print(f"방문 정점: {current}") # 방문 정점을 출력 for next_node in G.adjacent(current): # current의 모든 인접한 정점 확인 if not next_node.visited: # 방문하지 않은 정점이 있을 경우 DFS_recursion(G, next_node) # 재귀 호출
Python
복사

2.2. 너비 우선 탐색 (BFS)

동작 방식
시작 정점에서 가까운 정점부터 탐색
큐를 사용하여 주변 정점을 순차적으로 관리
시간 복잡도
인접 리스트 O(|V| + |E|)
인접 행렬 O(|V|^2)
구현
BFS (G, s) { Enqueue(Queue, s); s.flag = TRUE; while (Queue != NULL) { c = Dequeue(Queue); 정점 c를 방문 정점으로 출력; for (v ← c의 모든 인접한 정점) { if (v.flag == FALSE) { Enqueue(Queue, v); v.flag = TRUE; } } } }
C
복사
from collections import deque def BFS(G, s): Queue = deque() # 큐 생성 Queue.append(s) # 시작 정점을 큐에 삽입 s.flag = True # 시작 정점을 방문 표시 while Queue: # 큐가 비어있지 않을 동안 반복 c = Queue.popleft() # 큐에서 정점을 꺼냄 print(f"방문 정점: {c}") # 정점 c를 방문 정점으로 출력 for v in G.adjacent(c): # c의 모든 인접한 정점을 확인 if not v.flag: # 방문하지 않은 정점일 경우 Queue.append(v) # 큐에 삽입 v.flag = True # 방문 표시
Python
복사

3. 그래프 순회의 응용

3.1. 위상 정렬

정의
방향 비순환 그래프(DAG)에서 모든 정점을 간선의 방향에 맞춰 한 줄로 정렬
무사이클 방향 그래프에서 모든 간선이 한 방향으로만 향하도록 정점을 한줄로 나열하는 것
알고리즘
1.
DFS를 수행하며 스택에 정점을 저장
2.
스택에서 꺼낸 순서의 역순으로 정렬
예시
활용
작업 스케줄링, 의존성 그래프

3.2. 그래프의 연결성

정의
정점 간의 연결 관계를 다루는 것
연결 성분
정의
무방향 그래프에서 연결된 최대 정점 집합
무방향 그래프에서 임의의 두 정점 간의 경로가 존재하는 최대 부분 그래프
알고리즘
DFS 또는 BFS를 수행하며, 연결된 모든 정점을 하나의 성분으로 그룹화
강연결 성분
정의
방향 그래프에서 양방향 경로가 존재하는 최대 정점 집합
방향 그래프에서 임의의 두 정점 사이에 양방향의 경로가 존재하는 최대 부분 그래프
알고리즘
1.
DFS를 수행하여 각 정점의 방문 완료 순서(방문 순서의 역순) 기록
2.
간선의 방향을 뒤집은 그래프에서, 방문 완료 순서의 역순으로 DFS 수행.
3.
각 DFS 결과를 강연결 성분으로 처리.
예시