• data-structure
  • graph

그래프: 인접 행렬과 인접 리스트

그래프의 개념과 인접 행렬·인접 리스트 구현의 장단점, 연산별 시간 복잡도 차이, 트리와의 관계를 정리한다.

시리즈 · 자료구조 · 알고리즘9 / 13
  1. 시간 복잡도와 공간 복잡도
  2. 재귀 함수와 꼬리 재귀 최적화
  3. 연결 리스트(Linked List)
  4. 스택과 큐: 원형 큐 구현과 덱
  5. 해시 테이블: 해시 함수와 충돌 처리
  6. 트리와 이진 탐색 트리
  7. 힙(Heap)과 우선순위 큐
  8. 균형 이진 탐색 트리: AVL, Red-Black, B-Tree
  9. 그래프: 인접 행렬과 인접 리스트
  10. 최단 경로 알고리즘: BFS, 다익스트라, 벨만-포드, 플로이드-워셜, A*
  11. 최소 신장 트리(MST): Kruskal, Prim, Union-Find
  12. 정렬 알고리즘: 퀵·병합·기수 정렬부터 Timsort까지
  13. Thread-Safe 자료구조: Python GIL과 Java ConcurrentHashMap

그래프

연결되어 있는 원소 간의 관계를 나타낸 자료구조로, 정점(노드)과 간선으로 이루어진다.

  • 완전 그래프: 모든 정점이 서로 연결되어 있는 그래프
  • 부분 그래프: 어떤 그래프의 정점과 간선 일부로 이루어진 그래프
  • 가중 그래프: 간선에 가중치가 있는 그래프

구현 방법

아래에서 N은 정점의 수, E는 간선의 수이다.

인접 행렬

N × N 행렬에 간선의 정보를 저장하는 방법이다. matrix[i][j]에 정점 i와 j 사이의 간선 유무(또는 가중치)를 기록한다.

그래프의 간선 정보를 N × N 행렬로 표현한 인접 행렬

장점

  • 두 정점 사이의 간선 확인과 간선 추가 / 삭제가 O(1)로 빠르다.

단점

  • 간선의 개수와 상관없이 공간 복잡도가 O(N²)이다.
  • 정점의 추가 / 삭제가 느리다. 행렬을 다시 만들어야 하므로 O(N²)이다.
  • 그래프의 모든 간선을 확인하려면 O(N²)이 걸린다.

정점의 개수가 상대적으로 적고 간선이 많은 밀집 그래프(Dense Graph) 에 적합하다.

인접 리스트

정점마다 자신과 연결된 정점들의 목록을 리스트로 저장하는 방법이다.

정점마다 연결된 정점들을 리스트로 이어 표현한 인접 리스트

장점

  • 존재하는 간선만 저장하므로 메모리 효율이 좋다.
  • 특정 정점에 인접한 정점들을 바로 찾을 수 있다.
  • 정점의 추가가 빠르다.
  • 새로운 간선을 O(1)에 추가할 수 있다.
  • 그래프의 모든 간선을 확인하는 데 O(N + E)가 걸린다.

단점

  • 두 정점 사이에 간선이 있는지 확인하려면 리스트를 따라가야 하므로 오래 걸린다.

정점의 개수가 많고 간선이 상대적으로 적은 희소 그래프(Sparse Graph) 에 적합하다.

연산별 시간 복잡도 비교

연산 인접 행렬 인접 리스트
두 정점이 연결되어 있는지 확인 O(1) O(N)
한 정점에 연결된 모든 정점 찾기 O(N) O(해당 정점의 간선 수)
모든 간선 확인 O(N²) O(N + E)
공간 O(N²) O(N + E)

한 정점에 연결된 정점을 찾을 때 인접 행렬은 간선이 적어도 무조건 한 행 전체를 확인해야 하므로, 이 연산은 인접 리스트가 더 효율적이다.

정점이 N개, 간선이 N³개라면 어떻게 구현하는 것이 좋을까?

간선의 수가 정점의 수에 비해 매우 많은 경우이다. 인접 리스트의 메모리 이점이 사라지므로, 간선의 확인과 삽입 / 삭제가 O(1)인 인접 행렬로 구현하는 것이 효율적이다.

사이클이 없는 그래프는 모두 트리일까

사이클은 한 정점에서 출발해 간선을 따라 돌아다니다가 다시 출발점으로 돌아올 수 있는 경로를 말한다.

사이클이 없다고 해서 모두 트리인 것은 아니다. 아래 그래프는 방향 간선을 따라가도 출발점으로 돌아올 수 없으므로 사이클이 없지만, 한 정점으로 들어오는 간선이 두 개여서 부모가 둘인 셈이므로 트리가 아니다. 또한 사이클이 없더라도 그래프가 여러 조각으로 떨어져 있으면 트리가 아니다.

세 정점이 방향 간선으로 이어져 사이클은 없지만 한 정점에 간선 두 개가 들어오는 그래프

트리가 되려면 사이클이 없으면서 모든 정점이 연결되어 있어야 하고, 루트를 제외한 모든 정점의 부모가 하나여야 한다.