시작 정점으로부터 가까운 정점을 먼저 방문하고 멀리 떨어져 있는 정점을 나중에 방문하는 알고리즘이다.
시작 정점을 지나고 나면 깊이가 1인 모든 정점을 방문하고, 그다음에는 깊이가 2인 모든 정점을 방문한다.
이런 식으로 한 단계씩 깊이를 더해가며 해당 깊이에 있는 모든 정점들을 방문해 나가다가 나중에는 더 이상 방문할 곳이 없을 때 탐색을 종료한다.
루트 노드(혹은 다른 임의의 노드)에서 시작해서 인접한 노드를 먼저 탐색하는 방법
사용하는 경우: 두 노드 사이의 최단 경로 혹은 임의의 경로를 찾고 싶을 때 이 방법을 선택한다.
큐(Queue)를 이용
정점의 개수, 간선의 개수, 탐색을 시작할 정점을 번호를 입력받는다.
노드 방문 여부를 검사하기 위한 boolean 배열도 선언한다.
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); // 정점의 개수
int m = sc.nextInt(); // 간선의 개수
int v = sc.nextInt(); // 탐색을 시작할 정점의 번호
boolean visited[] = new boolean[n + 1]; // 방문 여부를 검사할 배열
LinkedList<Integer>[] adjList = new LinkedList[n + 1];
for (int i = 0; i <= n; i++) {
adjList[i] = new LinkedList<Integer>();
}
// 두 정점 사이에 여러 개의 간선이 있을 수 있다.
// 입력으로 주어지는 간선은 양방향이다.
for (int i = 0; i < m; i++) {
int v1 = sc.nextInt();
int v2 = sc.nextInt();
adjList[v1].add(v2);
adjList[v2].add(v1);
}
for (int i = 1; i <= n; i++) {
Collections.sort(adjList[i]); // 방문 순서를 위해 오름차순 정렬
}
System.out.println("BFS - 인접리스트");
bfs_list(v, adjList, visited);
처음 BFS 함수를 호출하면 int v에 탐색을 시작할 정점의 번호가 들어있고, 이 시작 정점부터 탐색을 시작한다.
큐를 생성하고 시작 정점 v의 값을 큐에 넣는다.
public static void bfs_list(int v, LinkedList<Integer>[] adjList, boolean[] visited) {
Queue<Integer> queue = new LinkedList<Integer>();
visited[v] = true;
queue.add(v);
while(queue.size() != 0) {
v = queue.poll();
System.out.print(v + " ");
Iterator<Integer> iter = adjList[v].listIterator();
while(iter.hasNext()) {
int w = iter.next();
if(!visited[w]) {
visited[w] = true;
queue.add(w);
}
}
}
}
int[][] adjArray = new int[n+1][n+1];
// 두 정점 사이에 여러 개의 간선이 있을 수 있다.
// 입력으로 주어지는 간선은 양방향이다.
for(int i = 0; i < m; i++) {
int v1 = sc.nextInt();
int v2 = sc.nextInt();
adjArray[v1][v2] = 1;
adjArray[v2][v1] = 1;
}
System.out.println("BFS - 인접행렬");
bfs_array(v, adjArray, visited);
public static void bfs_array(int v, int[][] adjArray, boolean[] visited) {
Queue<Integer> q = new LinkedList<>();
int n = adjArray.length - 1;
q.add(v);
visited[v] = true;
while (!q.isEmpty()) {
v = q.poll();
System.out.print(v + " ");
for (int i = 1; i <= n; i++) {
if (adjArray[v][i] == 1 && !visited[i]) {
q.add(i);
visited[i] = true;
}
}
}
}
전체 코드
1. 인접 리스트로 구현한 BFS
import java.util.*;
public class BFS_List {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); // 정점의 개수
int m = sc.nextInt(); // 간선의 개수
int v = sc.nextInt(); // 탐색을 시작할 정점의 번호
boolean visited[] = new boolean[n + 1]; // 방문 여부를 검사할 배열
LinkedList<Integer>[] adjList = new LinkedList[n + 1];
for (int i = 0; i <= n; i++) {
adjList[i] = new LinkedList<Integer>();
}
// 두 정점 사이에 여러 개의 간선이 있을 수 있다.
// 입력으로 주어지는 간선은 양방향이다.
for (int i = 0; i < m; i++) {
int v1 = sc.nextInt();
int v2 = sc.nextInt();
adjList[v1].add(v2);
adjList[v2].add(v1);
}
for (int i = 1; i <= n; i++) {
Collections.sort(adjList[i]); // 방문 순서를 위해 오름차순 정렬
}
System.out.println("BFS - 인접리스트");
bfs_list(v, adjList, visited);
}
// BFS - 인접리스트
public static void bfs_list(int v, LinkedList<Integer>[] adjList, boolean[] visited) {
Queue<Integer> queue = new LinkedList<Integer>();
visited[v] = true;
queue.add(v);
while(queue.size() != 0) {
v = queue.poll();
System.out.print(v + " ");
Iterator<Integer> iter = adjList[v].listIterator();
while(iter.hasNext()) {
int w = iter.next();
if(!visited[w]) {
visited[w] = true;
queue.add(w);
}
}
}
}
}
입력
5 5 3
5 4
5 2
1 2
3 4
3 1
출력
BFS - 인접리스트
3 1 4 2 5
import java.util.*;
public class BFS_Array {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); // 정점의 개수
int m = sc.nextInt(); // 간선의 개수
int v = sc.nextInt(); // 탐색을 시작할 정점의 번호
boolean visited[] = new boolean[n + 1]; // 방문 여부를 검사할 배열
int[][] adjArray = new int[n+1][n+1];
// 두 정점 사이에 여러 개의 간선이 있을 수 있다.
// 입력으로 주어지는 간선은 양방향이다.
for(int i = 0; i < m; i++) {
int v1 = sc.nextInt();
int v2 = sc.nextInt();
adjArray[v1][v2] = 1;
adjArray[v2][v1] = 1;
}
System.out.println("BFS - 인접행렬");
bfs_array(v, adjArray, visited);
}
// BFS - 인접행렬
public static void bfs_array(int v, int[][] adjArray, boolean[] visited) {
Queue<Integer> q = new LinkedList<>();
int n = adjArray.length - 1;
q.add(v);
visited[v] = true;
while (!q.isEmpty()) {
v = q.poll();
System.out.print(v + " ");
for (int i = 1; i <= n; i++) {
if (adjArray[v][i] == 1 && !visited[i]) {
q.add(i);
visited[i] = true;
}
}
}
}
}
입력
4 5 1 3
1 2
1 3
1 4
2 4
3 4
출력
BFS - 인접행렬
1 2 3 4
정점의 수가 n이고, 간선의 수가 e인 그래프의 경우
희소 그래프인 경우 인접 리스트의 사용이 인접 행렬보다 유리
(희소 그래프는 그래프 내에 적은 수의 간선을 가지는 그래프로 인접 행렬을 사용하면 메모리의 낭비가 크기 때문)
연습문제
백준 1260번 : DFS와 BFS