그래프의 탐색 : 하나의 정점으로부터 시작하여 차례대로 모든 정점들을 한 번씩 방문하는 것
Ex) 특정 도시에서 다른 도시로 갈 수 있는지 없는지, 전자 회로에서 특정 단자와 단자가 서로 연결되어 있는지 확인
정의 : 그래프의 탐색 알고리즘 중 하나로 루트 노드(혹은 다른 임의의 노드)에서 시작해서 다음 분기(branch)로 넘어가기 전에 해당 분기를 완벽하게 탐색하는 방법
EX) 미로를 탐색할 때 한 방향으로 갈 수 있을 때까지 계속 가다가 더 이상 갈 수 없게 되면 다시 가장 가까운 갈림길로 돌아와서 이곳으로부터 다른 방향으로 다시 탐색을 진행하는 방법과 유사하다.
정점 A
로 부터 시작
정점 C
를 방문
정점 D
를 방문
정점 E
를 방문
정점 B
를 방문
정점 E
로 돌아와 인접 정점 중 방문하지 않은 정점을 확인
정점 D
로 돌아와 인접 정점 중 방문하지 않은 정점을 확인
정점 C
로 돌아와 인접 정점 중 방문하지 않은 정점을 확인
정점 A
로 돌아와 인접 정점 중 방문하지 않은 정점을 확인
탐색 완료
방문 순서 :A
→ C
→ D
→ E
→ B
구현 방법
탐색 시작 노드를 스택에 삽입하고, 방문 처리한다.
스택의 최상단 노드에 방문하지 않은 인접 노드가 있으면 그 인접 노드를 스택에 넣고 방문 처리하고, 방문하지 않은 인접 노드가 없으면 스택에서 최상단 노드를 꺼낸다.
위의 1번과 2번 과정을 더 이상 수행할 수 없을 때까지 반복한다.
구현 코드
class dfsByStack {
boolean sizeSetting; // 초기 세팅
Stack<Integer> stack; // 재귀적 방법을 위한 스택
HashSet<Integer> visited; // 방문 기록
ArrayList<Integer> result; // 결과 리스트
dfsByStack() {
sizeSetting = false;
}
public List<Integer> dfs(int[][] graph, int startNode) {
if (!sizeSetting) { // 초기 세팅
visited = new HashSet();
stack = new Stack<>();
result = new ArrayList<>(graph.length - 1);
sizeSetting = true;
}
visited.add(startNode);
stack.push(startNode);
while (!stack.isEmpty()) {
Integer node = stack.pop();
result.add(node);
for (int vertex : graph[node]) {
if (!visited.contains(vertex)) {
stack.push(vertex);
visited.add(vertex);
}
}
}
sizeSetting = false; // 초기 설정값 false
return result;
}
}
깊이 우선 탐색(DFS)의 시간 복잡도
정의 : 그래프의 탐색 알고리즘 중 하나로 루트 노드(혹은 다른 임의의 노드)에서 시작해서 인접한 노드를 먼저 탐색하는 방법
Ex) 지구 상에 존재하는 모든 친구 관계를 그래프로 표현한 후 A 와 B 사이에 존재하는 경로를 찾는 경우
정점 A
를 시작으로 방문 처리 이후 큐에 삽입
정점 A
를 큐에서 뽑아 내고 인접 정점 C
, B
를 방문 처리 후 큐에 삽입
정점 C
를 큐에서 뽑아 내고 인접 정점 D
를 방문 처리 후 큐에 삽입
( 이미 방문한 A
정점은 무시한다. )
정점 B
를 큐에서 뽑아 내고 인접 정점 E
를 방문 처리 후 큐에 삽입
( 이미 방문한 A
, D
정점은 무시한다. )
정점 D
를 큐에서 뽑아 내고 방문하지 않은 인접 정점이 없기 때문에 무시
정점 E
큐에서 뽑아 내고 방문하지 않은 인접 정점이 없기 때문에 무시
탐색 완료
방문 순서 :A
→ C
→ B
→ D
→ E
탐색 시작 노드를 큐에 삽입하고 방문 처리한다.
큐에서 노드를 꺼내 해당 노드의 인접 노드 중에서 방문하지 않은 노드를 모두 큐에 삽입하고 방문 처리한다.
위의 1번과 2번 과정을 더 이상 수행할 수 없을 때까지 반복한다.
구현코드
class bfsByQueue {
boolean sizeSetting;
HashSet<Integer> visited;
Queue<Integer> queue;
ArrayList<Integer> result;
bfsByQueue() {
sizeSetting = false;
}
public List<Integer> bfs(int[][] graph, int startNode) {
if (!sizeSetting) {
visited = new HashSet<>();
result = new ArrayList<>(graph.length);
queue = new LinkedList<>();
sizeSetting = true;
}
result.add(startNode);
visited.add(startNode);
queue.add(startNode);
while (!queue.isEmpty()) {
Integer visitedNode = queue.poll();
for (Integer vertex : graph[visitedNode]) {
if (!visited.contains(vertex)) {
result.add(vertex);
visited.add(vertex);
queue.add(vertex);
}
}
}
sizeSetting = false;
return result;
}
}
너비 우선 탐색(BFS)의 시간 복잡도
- | DFS | BFS |
---|---|---|
동작방식 | 한 방향으로 깊이 탐색하다 없으면 돌아와 탐색 | 루트 노드부터 인접 노드들을 방문하고 해당 노드들의 인접 노드를 차례로 탐색 |
동작 원리 | 재귀적 방식을 이용 | 큐를 이용하여 인접 노드 탐색 |
구현 방식 | 재귀함수나 스택을 이용 | 큐 이용 |
시간 복잡도 | O(V+E) | O(V+E) |