Files
hello-algo/ko/docs/chapter_graph/graph_operations.md
T
Yudong Jin 2f561d3d51 feat(ko): add the Korean online edition (#2006)
* feat(ko): add the complete Korean online edition

* Use UTF-8 for Python CI output on Windows

* Remove print-book promotion from the Korean site

* fix(ko): preserve emphasis before Korean particles
2026-10-29 03:46:43 +08:00

6.0 KiB

그래프의 기본 연산

그래프의 기본 연산은 '간선'에 대한 연산과 '정점'에 대한 연산으로 나뉜다. '인접 행렬'과 '인접 리스트' 중 어느 표현을 사용하는지에 따라 구현 방법이 달라진다.

인접 행렬 기반 구현

정점 수가 $n$인 무방향 그래프가 주어졌을 때 각 연산은 아래 그림과 같이 구현한다.

  • 간선 추가 또는 삭제: 인접 행렬에서 해당 간선을 직접 수정하면 되며, O(1) 시간이 걸린다. 무방향 그래프이므로 두 방향의 간선을 함께 갱신해야 한다.
  • 정점 추가: 인접 행렬의 끝에 행과 열을 하나씩 추가하고 모두 $0$으로 채운다. O(n) 시간이 걸린다.
  • 정점 삭제: 인접 행렬에서 행과 열을 하나씩 삭제한다. 첫 번째 행과 열을 삭제할 때가 최악의 경우로, (n-1)^2 개 원소를 '왼쪽 위로 이동'해야 하므로 O(n^2) 시간이 걸린다.
  • 초기화: 정점 n 개를 전달받아 길이가 $n$인 정점 리스트 vertices를 초기화하는 데 O(n) 시간이 걸린다. n \times n 크기의 인접 행렬 adjMat을 초기화하는 데는 O(n^2) 시간이 걸린다.

=== "<1>" 인접 행렬의 초기화, 간선 추가와 삭제, 정점 추가와 삭제

=== "<2>" 인접 행렬에 간선 추가

=== "<3>" 인접 행렬에서 간선 삭제

=== "<4>" 인접 행렬에 정점 추가

=== "<5>" 인접 행렬에서 정점 삭제

다음은 인접 행렬로 그래프를 표현한 구현 코드다.

[file]{graph_adjacency_matrix}-[class]{graph_adj_mat}-[func]{}

인접 리스트 기반 구현

무방향 그래프의 전체 정점 수가 n, 전체 간선 수가 $m$이라면 아래 그림의 방법으로 각 연산을 구현할 수 있다.

  • 간선 추가: 해당 정점에 대응하는 연결 리스트 끝에 간선을 추가한다. O(1) 시간이 걸린다. 무방향 그래프이므로 두 방향의 간선을 함께 추가해야 한다.
  • 간선 삭제: 해당 정점에 대응하는 연결 리스트에서 지정한 간선을 찾아 삭제한다. O(m) 시간이 걸린다. 무방향 그래프에서는 두 방향의 간선을 함께 삭제해야 한다.
  • 정점 추가: 인접 리스트에 연결 리스트 하나를 추가하고 새 정점을 그 연결 리스트의 머리 노드로 둔다. O(1) 시간이 걸린다.
  • 정점 삭제: 인접 리스트 전체를 순회하며 지정한 정점이 포함된 모든 간선을 삭제한다. O(n + m) 시간이 걸린다.
  • 초기화: 인접 리스트에 정점 n 개와 간선 2m 개를 만든다. O(n + m) 시간이 걸린다.

=== "<1>" 인접 리스트의 초기화, 간선 추가와 삭제, 정점 추가와 삭제

=== "<2>" 인접 리스트에 간선 추가

=== "<3>" 인접 리스트에서 간선 삭제

=== "<4>" 인접 리스트에 정점 추가

=== "<5>" 인접 리스트에서 정점 삭제

다음은 인접 리스트의 구현 코드다. 위 그림과 비교하면 실제 코드에는 다음 차이가 있다.

  • 정점을 편리하게 추가하고 삭제하며 코드를 간단하게 만들기 위해 연결 리스트 대신 리스트(동적 배열)를 사용한다.
  • 해시 테이블로 인접 리스트를 저장한다. key는 정점 인스턴스이고, value는 그 정점의 인접 정점 리스트(연결 리스트)다.

또한 인접 리스트에서 정점을 나타내기 위해 Vertex 클래스를 사용한다. 인접 행렬처럼 리스트 인덱스로 정점을 구분한다면 인덱스가 $i$인 정점을 삭제할 때 인접 리스트 전체를 순회하면서 $i$보다 큰 모든 인덱스를 $1$씩 줄여야 하므로 매우 비효율적이기 때문이다. 반면 정점마다 고유한 Vertex 인스턴스를 사용하면 어느 정점을 삭제해도 다른 정점을 수정할 필요가 없다.

[file]{graph_adjacency_list}-[class]{graph_adj_list}-[func]{}

효율 비교

그래프에 정점 n 개와 간선 m 개가 있다고 하자. 아래 표는 인접 행렬과 인접 리스트의 시간 효율과 공간 효율을 비교한다. 여기서 인접 리스트(연결 리스트)는 이 절의 구현에 해당하며, 인접 리스트(해시 테이블)는 모든 연결 리스트를 해시 테이블로 바꾼 구현을 뜻한다.

표   인접 행렬과 인접 리스트 비교

인접 행렬 인접 리스트(연결 리스트) 인접 리스트(해시 테이블)
인접 여부 확인 O(1) O(n) O(1)
간선 추가 O(1) O(1) O(1)
간선 삭제 O(1) O(n) O(1)
정점 추가 O(n) O(1) O(1)
정점 삭제 O(n^2) O(n + m) O(n)
메모리 사용량 O(n^2) O(n + m) O(n + m)

위 표만 보면 인접 리스트(해시 테이블)의 시간 효율과 공간 효율이 가장 좋아 보인다. 하지만 실제로는 배열 접근이나 대입 한 번이면 되는 인접 행렬의 간선 연산이 더 효율적이다. 종합하면 인접 행렬은 '공간을 더 써서 시간을 절약하는' 원리를, 인접 리스트는 '시간을 더 써서 공간을 절약하는' 원리를 보여 준다.