그래프 탐색

그래프의 기본 개념과 탐색 방법

그래프 개념

정점과 간선

  • 정점 (vertex)

    • 노드라고 불리며 그래프를 형성하는 기본 단위이다.

    • 분할할 수 없는 객체이자, 점으로 표현되는 점, 위치, 사람 등이 될 수 있다.

  • 간선 (Edge)

    • 정점을 잇는 선으로, 관계 경로 등이 될 수 있다.

    • 간선에 방향에 따라 단방향간선, 양방향 간선으로 구분할 수 있다.

  • 그래프 (Graph)

    • 정점과 간선의 집합

indegree와 outdegree

  • indgree : 정점으로 들어오는 간선

  • outdegree : 정점으로 나가는 간선

  • 보통 정점은 약자로 V 또는 U라고 표시하며 U(From)로부터 V(To)로 간다고 표현한다.

가중치

  • 노드에서 다른 노드까지의 비용으로, 간선 비용의 합이다.

트리

자식 노드와 부모 노드로 이루어진 계층으로, 무방향 그래프이며 사이클이 없다

특징

  • 그래프(정점과 간선의 집합)의 일종이다.

  • 부모, 자식 계층 구조를 가진다.

  • V-1 = E라는 특징이 있다.

    • 정점 : Vertex

    • 간선 : Edge

    • 간선 수 = 노드 수 - 1

  • 임의의 두 노드 사이의 경로는 유일무이하게 존재한다.

    • 즉, 트리 내 특정 노드까지의 경로는 반드시 존재하며, 하나만 존재한다.

  • 루트, 내부, 리프노드로 구성된다.

트리의 높이와 레벨

  • 트리의 높이

    • 루트노드부터 최하단 리프노드까지의 길이

  • 서브트리

    • 트리 내에 있는 트리 (부분 집합)

  • 깊이

    • 각 노드마다 다르며, 루트 노드에서 특정 노드까지 최단 거리로 갔을 때의 거리

  • 레벨

    • 보통 깊이와 같은 의미를 지닌다.

    • 루트노드의 시작 레벨에 따라 상대적으로 결정된다.

      • 1번 노드가 0레벨이라면, 2번노드는 1

      • 1번 노드가 1레벨이라면, 2번노드는 2

    • 트리로 이루어진 집합

이진트리와 이진탐색트리

이진트리 (BT, BinaryTree)

  • 각 노드의 자식 노드 수가 2개 이하로 구성되어있는 트리이다.

    • 정이진 트리(full binary tree) : 자식노드가 0개 또는 2개

    • 완전 이진 트리 (complete binary tree) : 왼쪽부터 채워져있는 트리로, 마지막 레벨을 제외하고는 완전히 채워져있으며, 마지막 레벨은 왼쪽부터 채워진다.

    • 변질 이진 트리 (degenerate binary tree) : 자식 노드가 하나밖에 없는 이진 트리

    • 포화 이진 트리 (Perfect binary tree) : 모든 노드가 가득 차 있는 이진트리

    • 균형 이진 트리 (balanced binary tree) : 모든 노드의 왼쪽 하위 트리와 오른쪽 하위 트리의 차이가 1 이하인 트리이다. Map, set을 구성하는 레드블랙트리는 균형 이진트리 중 하나이다.

이진 탐색 트리 (BST, Binary Search Tree)

  • 이진 트리의 일종으로, 오른쪽 하위 트리에는 노드의 값보다 큰 값이 있는 노드만 포함되고, 왼쪽 하위트리에는 노드의 값보다 작은 값이 들어있는 트리이다.

  • 검색에 유리하다.

    • 10을 찾는 과정에서 25보다 10이 작으므로, 왼쪽 노드를 탐색한다.

      → 20보다 작으므로 왼쪽 노드로 탐색한다 → 10을 찾을 수 있다.

    • Up and down도 binary search tree에 들어간다.

  • 이진탐색트리의 시간복잡도

    • 위 사진처럼 균형잡히게 분포되었다면 탐색, 삽입, 삭제, 수정 모두 O(logN)이다.

  • 이진 탐색 트리의 모양은 노드 삽입 순서에 따라 달라진다. 1, 2, 3 순서로 삽입이 된다면 선형적 자료구조가 된다.

    • 이런 모양이 된다면, 탐색에 최악의 경우 O(logN)이 아닌 O(N)이 된다.

  • 삽입 순서에 상관 없이 트리의 노드를 회전시키는 방법 등을 통해 균형 잡게 만드는 것을 AVL 트리, 레드블랙트리가 있다.

    • map 자료구조는, 삽입 탐색 삭제 수정의 시간복잡도가 O(logN)임을 보장받는데, 그 이유가 균형잡힌 트리인 레드블랙트리를 기반으로 구현되어있기 때문이다.

그래프 구현과 탐색

그래프를 컴퓨터가 이해할 수 있도록 코드로 작성해야한다.

인접행렬

  • 정점과 간선의 관계를 나타내는 2차원 행렬

  • true, false를 이용하여 연결되어있는지 표현한다.

인접리스트 (adjancency list)

  • 연결리스트럴 여러개 만들어 표현하는 방법이다.

  • 각 정점마다 연결리스트를 만들고, 연결된 정점을 저장한다.

인접행렬과 인접리스트의 차이

  1. 공간복잡도

    • 인접행렬 : O(V^2)

    • 인접리스트 : O(V + E)

      • 연결된 정점만 데이터가 들어간다.

      • 정점이 여러개가 있더라도 연결된 정점만 들어가므로, 간선의 개수만 들어가게 되는것이다

  2. (최악) 시간복잡도

    1. 간선 한 개 찾기

      • 노드 i에서 노드 j로 가는 간선이 있는가?

        • 인접행렬 = O(1)

        • 인접리스트 = O(V)

    2. 모든 간선 찾기

      • 인접행렬 : O(V^2)

      • 인접리스트 : O(V + E)

  3. 그래서 언제 인접 리스트, 인접 행렬을 써야할까?

    • 그래프가 희소한 경우(sparse) 인접리스트, 조밀할 때(dense)에는 인접 행렬을 쓴다.

    • 연결된 정점이 많이 없을 때에는 인접 리스트를 쓰는 것이 더 빠르고 좋다.

      • 인접행렬의 경우 무식하게 이차원 배열을 만들게 된다.

      • 연결되지 않은 노드들을 위해서도 이차원 배열을 만들게 된다.

    • 그래프가 조밀할 때 (간선이 너무 많을 때) 인접 행렬이 더 좋다.

      • 어차피 노드들이 모두 연결되어있다면 메모리적 효율성이 동일하므로, 하나의 간선을 찾는데에 속도가 더 빠른 인접 행렬이 더 빠르다.

    • 보통 코딩테스트에는 희소한 그래프가 나오니 연결리스트로 사용하는게 좋지만, 인접행렬로 주어진다면 주어진대로 문제를 푸는 것이 좋다.

연결된 컴포넌트(Connected component)

  • 그래프 안에 하위그래프를 말하며, 하나의 덩어리라고 볼 수 있다.

  • 연결된 컴포넌트에 속한 모든 정점을 연결하는 경로가 있다는 특징이 있다.

  • 컴포넌트들에 번호를 붙여가며 색칠하는 알고리즘을 풀르드필(floodfill)이라고 한다.

    • 첫번재 연결된 컴포넌트에서 연결된 모든 노드는 1번

    • 두 번째 연결된 컴포넌트에서 연결된 모든 노드는 2번 이런 식으로

    • 해당 번호는 연결된 덩어리의 개수만큼만 나온다.

  • 만약 맵으로 주어지는 상황에서도 갈 수 있는 지점을 통해 정점의 집합을 만들 수 있다. 이를 기반으로 connected component로 만들어보자.

그래프 탐색 방법

  • 그래프를 탐색할 때 쓰는 알고리즘이다.

  • 인접한 노드들을 재귀적으로 방문하며, 방문한 정점은 다시 방문하지 않는다.

    • 분기마다 가장 멀리 있는 노드까지 탐색하는 알고리즘이다.

  • 수도코드

  • DFS 코드

  • 다음 깊이의 정점으로 이동하기 전, 현재 깊이의 모든 정점을 탐색하며, 방문한 정점은 다시 방문하지 않는 알고리즘이다.

    • 같은 가중치를 가진 그래프에서 최단 거리 알고리즘으로 쓰인다.

    • Layer별, Level 별로 탐색한다는 의미이다.

  • BFS 구현 방법

    • 자료구조 큐(Queue)를 사용하면 레벨 별로 탐색이 가능하다.

    • 수도코드 1

    • 수도코드 2 - 최단거리 배열로 쓸 수 있다.

  • Swift 구현

  • 시작지점이 다수인 경우

    • 큐에 푸시하는 지점도 다수가 되어야한다

    • 해당 지점들의 visited를 모두 1로 만들면서 시작해야한다.

  • BFS가 가중치가 같은 그래프 내에서만 최단거리로 쓰이는 이유

    • Level로 최단거리를 측정하기 때문이다.

    • 현재 방법으로는 각 간선마다 다른 가중치를 줄 수 없다.

    • 가중치가 다른 경우의 최단거리를 찾기 위해서는 다익스트라, 벨만포드 등을 써야한다.

DFS와 BFS 비교

문제에서 "퍼져나간다", "탐색한다"가 있는 경우 DFS와 BFS를 우선적으로 떠올려보자.

가중치가 동일한 그래프에서 최단거리를 구할 땐 BFS를 사용하

  • 시간복잡도 (동일하다)

    • 인접리스트: O(V + E)

    • 인접행렬 : O(V^2)

  • 차이점

    • DFS

      • 메모리를 덜 사용한다.

      • 절단점 등을 구할 수 있다. (고급 알고리즘)

      • 코드가 간단하며, 완전탐색의 경우 많이 사용한다.

    • BFS

      • 큐를 구현해야하므로 메모리를 더 쓴다.

      • 가중치가 같은 그래프 내에서 최단거리를 구할 수 있다.

트리순회

트리 자료구조에서 각 노드를 정확히 한 번만 체계적으로 방문하는 알고리즘이다.

방문 순서에 따라 순회방법이 결정된다.

  1. 후위순회(postorder traversal)

    • 자식들 노드 방문 후 자신을 방문한다. (왼쪽부터)

  2. 전위순회 (preorder traversal)

    • 자신 노드 방문 후 자식 노드를 방문한다.

    • DFS와 동일하다.

  3. 중위순회 (inorder traversal)

    • 왼쪽 자식 노드 → 자신 노드 → 오른쪽 자식 노드

  4. 레벨 순회

    • 같은 레벨을 탐색한다

    • BFS와 동일하다.

다익스트라 알고리즘

개념

  • 여러개의 노드가 있을 때, 특정 노드에서 출발하여 다른 노드로 가는 각각의 최단 경로를 구하는 알고리즘이다.

  • 음의 간선이 없을 때 정상적으로 동작한다. (0보다 작은 값을 가질 수 없다)

    • 현실 세계에서는 음의 간선으로 표현되지 않으므로 GPS 기본 알고리즘으로 채택되기도 한다.

알고리

  1. 출발 노드를 설정한다.

  2. 최단 거리 테이블을 초기화한다.

  3. 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드를 선택한다. (최소힙 사용)

  4. 최단 거리 테이블을 갱신한다.

코드

최소힙 코드

Last updated