[알고리즘] 그래프1
그래프
- 그래프
G = (V,E)
- 정점의 집합 V와 간선의 집합 E로 구성된 비선형 자료구조
- 방향성 여부에 따라 무방향 그래프와 방향 그래프로 구분된다.
- 간선에 비용이나 시간과 같은 의미를 갖는 가중치를 부여한 그래프를 가중 그래프라 한다.
- 정점 u에서 정점 v 사이의 간선을 무방향 그래프에서는 (u,v)로 표현하며, 방향 그래프에서는 <u,v>로 표현한다.
인접 행렬
- 그래프를 2차원 배열로 표현
- i=j인 대각선상의 값은 0이다.
- 일반 그래프 : 정점 i와 정점 j 사이에 간선이 존재하면 1, 존재하지 않으면 0이다.
- 가중 그래프 : 정점 i와 정점 j 사이에 간선이 존재하면 가중치 값, 존재하지 않으면 ∞이다.
인접 리스트
- 그래프를 연결 리스트로 표현
- 임의의 정점 u를 중심으로 인접한 모든 정점을 하나의 연결 리스트로 표현
- 일반 그래프 : 정점을 나타내는 필드와 링크 필드로 구성
- 가중 그래프 : 가중치를 저장하기 위한 필드가 추가로 필요
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
let paths = [];
const BFS = (arr) => {
let memo = {};
for (let item of arr) {
const [prev, next] = item;
if (memo[prev]) {
memo[prev].push(next);
} else {
memo[prev] = [next];
}
}
console.log(memo);
// {
// '1': [ 2, 4 ],
// '2': [ 1, 5 ],
// '3': [ 5 ],
// '4': [ 1 ],
// '5': [ 2, 3 ]
// }
let visited = {};
const DFS = (v, path) => {
if (v === 5) {
paths.push(path);
return;
}
if (memo[v]) {
visited[v] = true;
for (let item of memo[v]) {
//미방문 정점만 방문
if (!visited[item]) {
DFS(item, [...path, item]);
}
}
visited[v] = false;
}
};
DFS(1, [1]);
};
BFS([
[1, 2],
[1, 4],
[2, 1],
[2, 5],
[3, 5],
[4, 1],
[5, 2],
[5, 3]
]);
console.log(paths); //[[1,2,5]]
그래프 순회
- 방문 정점 : 방문이 완료된 정점
- 주변 정점 : 방문 정점에 인접한 정점 중에서 아직 방문하지 않은 정점
깊이 우선 탐색 (DFS)
- 스택 구조를 사용
- 최근의 주변 정점을 우선 방문
- 스택의 탑에 있는 정점에 대한 주변 정점이 존재하면 그중 하나의 정점을 스택에 삽입하고 방문한 정점으로 처리한다. 주변 정점이 없다면 스택의 탑에 있는 정점을 제거한다.
성능
- 인접 행렬로 표현하면
O(|V|²)
, 인접 리스트로 표현하면O(|V|+|E|)
- 순환 알고리즘 형태로 쉽게 구현할 수 있다.
너비 우선 탐색 (BFS)
- 큐 구조를 사용
- 주변 정점 중에서 오래된 것을 우선 방문
- 시작 정점을 기준으로 가장 인접한 정점을 우선으로 모두 방문한 후 시작 정점과의 거리가 점점 멀어지는 순서로 인접 정점들을 탐색
성능
- 인접 행렬로 표현하면
O(|V|²)
, 인접 리스트로 표현하면O(|V|+|E|)
위상 정렬
- 무사이클 방향 그래프에서 모든 간선이 한 방향으로만 향하도록 정점을 한 줄로 나열하는 것
- 깊이 우선 탐색을 활용하여 스택에서 삭제되는 정점을 역순으로 나열
성능
- 인접 행렬로 표현하면
O(|V|²)
, 인접 리스트로 표현하면O(|V|+|E|)
연결 성분
- 무방향 그래프에서 임의의 두 정점 간의 경로가 존재하는 최대 부분 그래프
- 깊이 우선 탐색이나 너비 우선 탐색을 활용하여 큐/스택이 비는 순간 그때까지 탐색한 정점들을 하나의 연결 성분으로 구성
강연결 성분
- 방향 그래프에서 임의의 두 정점 사이에 양방향의 경로가 존재하는 최대 부분 그래프
- (1) 깊이 우선 탐색으로 정점의 방문 완료 순서(방문 순서의 역순)를 구한다.
- (2) 모든 간선의 방향을 반대로 바꾼다.
- (3) 방문 완료 번호가 큰 것부터 깊이 우선 탐색을 수행하여 갈 수 있는 정점들의 각 리스트가 강연결 성분이 됨
최소 신장 트리
- 신장 트리
- 가중 무방향 그래프에서 모든 정점을 포함하는 트리
- 신장 트리에는 사이클이 존재하지 않는다.
- 정점의 개수
|V|=n
이면 트리에는 정확히 n-1개의 간선이 존재한다.
- 간선들의 가중치들의 합이 가장 작은 신장 트리
- 최소 신장 트리를 구하는 방법에는 크루스칼 알고리즘, 프림 알고리즘이 있다. (둘 다 욕심쟁이 방법)
크루스칼 알고리즘
- 간선이 없는 상태에서 시작해서 가중치가 가장 작은 간선부터 하나씩 골라서 사이클을 형성하지 않으면 해당 간선을 추가하는 방식
- 간선 (u,v)의 두 정점 u,v가 서로 다른 연결 성분에 속하면 사이클을 형성하지 않음
간선 (4,6)부터는 사이클이 형성되어 선택할 수 없다.
성능
O(|E|log|E|)
프림 알고리즘
- 임의의 한 정점에서 시작해서 연결된 정점을 하나씩 선택해 나가는 방법
- 선택된 정점의 집합 S와 선택되지 않은 정점의 집합 V-S를 잇는 간선 중에서 가중치가 가장 작은 간선을 선택해서 추가하는 방법
- 선택되지 않은 정점의 집합 V-S를 잇는 간선 중에서 가중치가 가장 작은 간선 (1,3)을 선택해 T에 추가하고, 정점 3을 S에 추가한다.
- 선택되지 않은 정점의 집합 V-S를 잇는 간선 중에서 가중치가 가장 작은 간선 (3,5)을 선택해 T에 추가하고, 정점 5을 S에 추가한다.
- 선택되지 않은 정점의 집합 V-S를 잇는 간선 중에서 가중치가 가장 작은 간선 (3,6)을 선택해 T에 추가하고, 정점 6을 S에 추가한다.
- 선택되지 않은 정점의 집합 V-S를 잇는 간선 중에서 가중치가 가장 작은 간선 (2,5)을 선택해 T에 추가하고, 정점 2을 S에 추가한다.
- 선택되지 않은 정점의 집합 V-S를 잇는 간선 중에서 가중치가 가장 작은 간선 (3,4)을 선택해 T에 추가하고, 정점 4을 S에 추가한다.
성능
- 인접 행렬로 표현하면
O(|V|²)
, 인접 리스트로 표현하면O((|V|+|E|)log|V|)
This post is licensed under CC BY 4.0 by the author.