ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [DFS/BFS] 개념정리3 - DFS과 BFS
    Algorithm/개념정리 2021. 7. 17. 14:29

    그래프 탐색이란? → 하나의 정점을 시작으로 다수의 정점을 방문하는 것

    DFS(Depth First Search)

    깊이 우선 탐색이라고도 부르며, 그래프에서 깊은 부분을 우선적으로 탐색하는 알고리즘

    이 알고리즘은 특정한 경로로 탐색하다가 특정한 상황에서 최대한 깊숙이 들어가서 노드를 방문한 후, 다시 돌아가 다른 경로로 탐색하는 알고리즘

    사용 자료구조 : 스택

    동작 과정 :

    1. 탐색 시작 노드를 스택에 삽입하고 방문 처리함
    2. 스택의 최상단 노드에 방문하지 않은 인접 노드가 있으면, 그 인접 노드를 스택에 넣고 방문처리 함
    3. 방문하지 않은 인접노드가 없으면 스택에서 최상단 노드를 꺼냄
    4. 2번의 과정을 더 이상 수행할 수 없을 때까지 반복함

    —> 방문 처리 : 스택에 한 번 삽입되어 처리된 노드가 다시 삽입되지 않게 체크하는 것을 의미함

    —> 일반적으로 인접 노드 중에서 방문하지 않은 노드가 여러 개 있으면 번호가 낮은 순위부터 처리함

    —> 탐색 순서 : 스택에서 pop된 순

     

    구현방식(2가지)

    A. 재귀함수로 구현

    import java.util.LinkedList;
    
    public class Main {
    
    	public static boolean[] visited = new boolean[9]; //방문 처리를 위한 배열 
    	public static LinkedList<LinkedList<Integer>> graph = new LinkedList<LinkedList<Integer>>(); //그래프 - 인접리스트로 구현 
    	
    	//그래프 간선 추가 (단방향 그래프)
    	public static void addEdge(LinkedList<LinkedList<Integer>> graph, int u, int v) {
    		graph.get(u).add(v);
    	}
    	
    	//DFS - 재귀함수로 구현 
    	public static void dfs(int startVertex) {
    		//현재 노드 방문 처리 
    		visited[startVertex] = true;
    		System.out.print(startVertex + " ");
    		//현재 노드와 인접한 다른 노드를 재귀적으로 방문함
    		for(int vertex : graph.get(startVertex))
    			if(!visited[vertex]) dfs(vertex);
    	}
    	
    	public static void main(String[] args) {
    		
    		//그래프 초기화
    		for(int i = 0; i < 9; i++)
    			graph.add(new LinkedList<Integer>()); //각 정점의 연결 리스트 생성 
    		
    		//그래프 간선 추가 
    		addEdge(graph, 1, 2);
    		addEdge(graph, 1, 3);
    		addEdge(graph, 1, 8);
    		
    		addEdge(graph, 2, 1);
    		addEdge(graph, 2, 7);
    		
    		addEdge(graph, 3, 1);
    		addEdge(graph, 3, 4);
    		addEdge(graph, 3, 5);
    		
    		addEdge(graph, 4, 3);
    		addEdge(graph, 4, 5);
    		
    		addEdge(graph, 5, 3);
    		addEdge(graph, 5, 4);
    		
    		addEdge(graph, 6, 7);
    		
    		addEdge(graph, 7, 2);
    		addEdge(graph, 7, 6);
    		addEdge(graph, 7, 8);
    		
    		addEdge(graph, 8, 1);
    		addEdge(graph, 8, 7);
    		
    		//DFS (깊이 우선 탐색) 
    		dfs(1);
    
    	}
    }

    B. 스택으로 구현  

    import java.util.LinkedList;
    import java.util.Stack;
    
    public class DFS_stack {
    
    	public static boolean[] visited = new boolean[9]; //방문 처리를 위한 배열 
    	public static LinkedList<LinkedList<Integer>> graph = new LinkedList<LinkedList<Integer>>(); //그래프 
    	
    	
    	//그래프 간선 추가 (단방향 그래프) 
    	public static void addEdge(LinkedList<LinkedList<Integer>> graph, int u, int v) {
    		graph.get(u).add(v);
    	}
    	
    	//DFS - 스택으로 구현 
    	public static void dfs(int startVertex) {
    		Stack<Integer> st = new Stack<>(); //스택 생성 
    		
    		st.push(startVertex); //시작 정점 스택 삽입 
    		
    		while(!st.isEmpty()) {
    			startVertex = st.pop(); //스택의 최상단 노드 반환(LIFO)
    			if(!visited[startVertex]) { //해당 정점이 방문되지 않았다면 
    				visited[startVertex] = true; //방문 체크 
    				System.out.print(startVertex + " ");
    				for(int vertex : graph.get(startVertex)) //인접 정점 중에서 
    					if(!visited[vertex]) st.push(vertex); //방문하지 않은 정점을 스택에 삽입 
    			}
    		}
    	}
    	
    	public static void main(String[] args) {
    		
    		//그래프 초기화
    		for(int i = 0; i < 9; i++)
    			graph.add(new LinkedList<Integer>()); //각 정점의 연결 리스트 생성 
    		
    		//그래프 간선 추가 
    		addEdge(graph, 1, 2);
    		addEdge(graph, 1, 3);
    		addEdge(graph, 1, 8);
    		
    		addEdge(graph, 2, 1);
    		addEdge(graph, 2, 7);
    		
    		addEdge(graph, 3, 1);
    		addEdge(graph, 3, 4);
    		addEdge(graph, 3, 5);
    		
    		addEdge(graph, 4, 3);
    		addEdge(graph, 4, 5);
    		
    		addEdge(graph, 5, 3);
    		addEdge(graph, 5, 4);
    		
    		addEdge(graph, 6, 7);
    		
    		addEdge(graph, 7, 2);
    		addEdge(graph, 7, 6);
    		addEdge(graph, 7, 8);
    		
    		addEdge(graph, 8, 1);
    		addEdge(graph, 8, 7);
    		
    		
    		
    		//DFS (깊이 우선 탐색) 
    		dfs(1);
    
    	}
    
    }

    BFS(Breadth First Search)

    '너비 우선 탐색'이라는 의미를 가지고, 가까운 노드부터 탐색하는 알고리즘임

    사용 자료구조 : 큐 (선입선출 방식) → 인접한 노드를 반복적으로 큐에 넣도록 알고리즘을 작성하면 먼저 들어온 것이 먼저 나가게 되어, 가까운 노드부터 탐색 진행하게 됨

    동작 과정 :

    1. 탐색 시작 노드를 큐에 삽입하고 방문 처리함
    2. 큐에서 노드를 꺼내 해당 노드의 인접 노드 중에서 방문하지 않은 노드를 모두 큐에 삽입하고 방문 처리함
    3. 2번의 과정을 더 이상 수행할 수 없을 때까지 반복함

    —> 탐색 순서 : 큐에 들어간 순서(큐는 선입선출 구조 이니까 큐에 들어간 순서가 곧 방문 순서)

     

    구현방식

    import java.util.LinkedList;
    import java.util.Queue;
    
    public class Main {
    
    	public static boolean[] visited = new boolean[9];
    	public static LinkedList<LinkedList<Integer>> graph = new LinkedList<LinkedList<Integer>>();
    	
    	public static void addEdge(LinkedList<LinkedList<Integer>> graph, int u, int v) {
    		graph.get(u).add(v);
    	}
    	
    	//BFS 정의 
    	public static void bfs(int startVertex) {
    		Queue<Integer> q = new LinkedList<>(); //큐 선언 
    		
    		q.offer(startVertex); //시작 노드 큐에 삽입 
    		visited[startVertex] = true; //시작 노드 방문 처리 
    		
    		//빈 큐가 될 때까지 반복
    		while(!q.isEmpty()) {
    			int vertex = q.poll(); //dequeue 
    			System.out.print(vertex + " ");
    			
    			//해당 정점과 인접하지만 아직 방문하지 않은 원소들을 큐에 삽입
    			for(int v : graph.get(vertex))
    				if(!visited[v]) {
    					q.offer(v); //enqueue 
    					visited[v] = true;
    				}
    		}
    	}
    	
    	public static void main(String[] args) {
    		//그래프 초기화 
    		for(int i = 0; i < 9; i++)
    			graph.add(new LinkedList<Integer>());
    		 
    		//그래프 간선 추가 
    		addEdge(graph, 1, 2);
    		addEdge(graph, 1, 3);
    		addEdge(graph, 1, 8);
    			
    		addEdge(graph, 2, 1);
    		addEdge(graph, 2, 7);
    				
    		addEdge(graph, 3, 1);
    		addEdge(graph, 3, 4);
    		addEdge(graph, 3, 5);
    				
    		addEdge(graph, 4, 3);
    		addEdge(graph, 4, 5);
    				
    		addEdge(graph, 5, 3);
    		addEdge(graph, 5, 4);
    				
    		addEdge(graph, 6, 7);
    				
    		addEdge(graph, 7, 2);
    		addEdge(graph, 7, 6);
    		addEdge(graph, 7, 8);
    				
    		addEdge(graph, 8, 1);
    		addEdge(graph, 8, 7);
    				
    		//BFS (넓이 우선 탐색) 
    		bfs(1);
    	}
    }

    추가)

    2차원 배열에서의 탐색 문제의 경우 —> 그래프 형태로 바꿔서 생각해보자!

    2차원 배열에서의 (row, col) 좌표 = 그래프의 정점

    2차원 배열에서의 상하좌우 인접 좌표 = 그래프에서 간선으로 연결된 정점들

     

     

    참고) '이것이 취업을 위한 코딩테스트다' 책 

     

    댓글

Designed by Tistory.