[이코테 with Java] DFS

2024. 1. 22. 15:53Java 기초개념

■ DFS


DFS는 Depth-First Search, "깊이 우선 탐색"이라고도 부르며, 그래프에서 깊은 부분을 우선적으로 탐색하는 알고리즘이다. 

DFS 이전에 그래프(Graph)의 기본적인 구조를 먼저 알아야 한다. 

그래프는 노드(Node)간선(Edge)으로 표현되며, 이때 노드를 정점(Vertex)라고도 말한다. 

또한, 두 노드가 간선으로 연결되어 있다면 '두 노드는 인접하다'라고 표현한다. 

 

프로그래밍에서는 그래프를 크게 2가지 방식으로 표현할 수 있다.

  • 인접 행렬(Adiacency Matrix): 2차원 배열로 그래프의 연결 관계를 표현하는 방식
  • 인접 리스트(Adjacency List): 리스트로 그래프의 연결 관계를 표현하는 방식 

 

 


 

 

 

1. 인접 행렬   -  2차원 배열에 각 노드가 연결된 형태를 기록하는 방식

  0 1 2
0 0 7 5
1 7 0 무한
2 5 무한 0

 

위의 그래프로 노드를 만들어보면, 0은 1과 2와 연결되어 있고, 1까지의 거리는 7, 2까지의 거리는 5이다.

1과 2는 연결되어 있지 않으므로 무한, 2도 1과 연결되어 있지 않으므로 무한이다. 

연결되어 있지 않은 노드끼리는 무한(Infinity) 비용이라고 작성한다. 

import java.util.*;

public class Main {
    public static final int INF = 999999999;

    // 2차원 리스트를 이용해 인접 행렬 표현
    public static int[][] graph = {
        {0, 7, 5},
        {7, 0, INF},
        {5, INF, 0}
    };

    public static void main(String[] args){
        // 그래프 출력
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < 3; j++){
                System.out.print(graph[i][j] + " ");
            }
            System.out.println();
        }
    }
}

 

결과

0 7 5
7 0 9999999
5 9999999 0

 

2. 인접 리스트  -  모든 노드에 연결된 노드에 대한 정보를 차례대로 연결하여 저장한다

import java.util.*;

class Node {
    private int index;
    private int distance;

    public Node(int index, int distance){
        this.index = index;
        this.distance = distance;
    }

    public void show(){
        System.out.print("(" + this.index + "," + this.distance + ") ");
    }
}

public class Main {
    // 행(Row)이 3개인 인접 리스트 표현
    public static ArrayList<ArrayList<Node>> graph = new ArrayList<ArrayList<Node>>();

    public static void main(String[] args){
        // 그래프 초기화
        for(int i = 0; i < 3; i++){
            graph.add(new ArrayList<Node>());
        }

        // 노드 0에 연결된 노드 정보 저장 (노드, 거리)
        graph.get(0).add(new Node(1, 7));
        graph.get(0).add(new Node(2, 5));

        // 노드 1에 연결된 노드 정보 저장 (노드, 거리)
        graph.get(1).add(new Node(0, 7));

        // 노드 2에 연결된 노드 정보 저장 (노드, 거리)
        graph.get(2).add(new Node(0, 5));

        // 그래프 출력
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < graph.get(i).size(); j++){
                graph.get(i).get(j).show();
            }
            System.out.println();
        }
    }
}

 

결과

(1, 7) (2, 5)
(0, 7)
(0, 5)

 

3. 인접 리스트와 인접 행렬의 차이

- 인접 행렬

장점: 특정한 두 노드가 연결되어 있는지에 대한 정보를 얻는 속도가 빠르다. 

단점: 모든 관계를 저장하므로 노드 개수가 많을수록 메모리가 불필요하게 낭비된다.

- 인접 리스트

장점: 연결된 정보만을 저장하기 때문에 메모리를 효율적으로 사용

단점: 특정한 두 노드가 연결되어 있는지에 대한 정보를 얻는 속도가 느리다.

 

 

4. DFS의 동작 과정

  1. 탐색 시작 노드를 스택에 삽입하고 방문 처리를 한다.
  2. 스택의 최상단 노드에 방문하지 않은 인접 노드가 있으면 그 인접 노드를 스택에 넣고 방문 처리를 한다. 방문하지 않은 인접 노드가 없으면 스택에서 최상단 노드를 꺼낸다. (인접 노드가 여러 개인 경우, 번호가 낮은 순서부터 처리)
  3. 2번 과정을 더 이상 수행할 수 없을 때까지 수행한다.

=> 여기서 "방문 처리"스택에 한 번 삽입되어 처리된 노드가 다시 삽입되지 않게 체크하는 것을 의미한다. 

     방문 처리를 함으로써 각 노드를 한 번씩만 처리할 수 있다. 

 

import java.util.*;

public class Main {
    public static boolean[] visited = new boolean[9];
    public static ArrayList<ArrayList<Integer>> graph = new ArrayList<ArrayList<Integer>>();

    // DFS 함수 정의
    public static void dfs(int x){
        // 현재 노드를 방문 처리
        visited[x] = true;
        System.out.print(x + " ");
        // 현재 노드와 연결된 다른 노드를 재귀적으로 방문
        for(int i = 0; i < graph.get(x).size(); i++){
            int y = graph.get(x).get(i);
            if(!visited[y]) dfs(y);
        }
    }

    public static void main(String[] args){
        // 그래프 초기화
        for(int i = 0; i < 9; i++){
            graph.add(new ArrayList<Integer>());
        }

        // 노드 1에 연결된 노드 정보 저장
        graph.get(1).add(2);
        graph.get(1).add(3);
        graph.get(1).add(8);

        // 노드 2에 연결된 노드 정보 저장
        graph.get(2).add(1);
        graph.get(2).add(7);

        // 노드 3에 연결된 노드 정보 저장
        graph.get(3).add(1);
        graph.get(3).add(4);
        graph.get(3).add(5);

        // 노드 4에 연결된 노드 정보 저장
        graph.get(4).add(3);
        graph.get(4).add(5);

        // 노드 5에 연결된 노드 정보 저장
        graph.get(5).add(3);
        graph.get(5).add(4);

        // 노드 6에 연결된 노드 정보 저장
        graph.get(6).add(7);

        // 노드 7에 연결된 노드 정보 저장
        graph.get(7).add(2);
        graph.get(7).add(6);
        graph.get(7).add(8);

        // 노드 8에 연결된 노드 정보 저장
        graph.get(8).add(1);
        graph.get(8).add(7);

        dfs(1);
    }
}

 

결과

1 2 7 6 8 3 4 5