에듀테크 프로젝트 대시보드
그래프 표현 (인접 리스트 vs 행렬)
이 사이트엔 이미 BFS/DFS, 다익스트라, 최소 신장 트리 같은 그래프 알고리즘 페이지가 여럿 있지만,
정작 "그래프를 코드로 어떻게 저장하는가"는 다루지 않았다. 알고리즘이 빠르게 도는지는 결국
자료구조 선택에 달려 있다 — 같은 그래프도 인접 행렬과 인접 리스트 중 무엇으로 담느냐에 따라
메모리와 속도가 완전히 달라진다. 이 페이지는 BFS/DFS(/graph-traversal) 같은 탐색 알고리즘의
선행 개념이다.
그래프(Graph)는 정점(Vertex, 노드) 들과 그것을 잇는 간선(Edge) 들의 모임이다. 간선에 방향이 있으면 방향 그래프(directed), 없으면 무방향 그래프(undirected)라 하고, 간선마다 비용(거리·시간 등) 숫자가 붙으면 가중치 그래프(weighted)라 한다.
간선에 화살표가 없다 — A-B 관계는 곧 B-A 관계와 같다. 친구 관계, 도로망 등.
화살표 방향으로만 이동 가능하고 숫자는 가중치(비용)다. 길찾기·환승 시간·네트워크 대역폭 등.
정점이 N개면 N×N 표를 만들고, matrix[i][j] = 1이면 i에서 j로 가는 간선이 있다는 뜻이다.
"i와 j가 연결돼 있는가?"를 표 한 칸 조회로 바로 알 수 있어 간선 존재 확인이 O(1)이다.
대신 정점 수와 무관하게 항상 N² 칸을 다 차지하므로 공간이 O(V²) — 간선이 거의 없는 그래프에도 빈 칸이 낭비된다.
각 정점마다 자신과 연결된 정점들의 리스트만 들고 있는다. 실제로 존재하는 간선 수만큼만 저장하므로 공간이 O(V+E) — 정점 목록 V개 + 간선 기록 E개뿐이다. 다만 "i와 j가 연결됐나?"를 확인하려면 i의 리스트를 처음부터 훑어야 하므로 간선 존재 확인이 O(degree(i))로, 행렬보다 느릴 수 있다.
행렬의 칸을 클릭하면 간선이 켜지거나 꺼진다. 무방향 모드에서는 (i,j)와 (j,i)가 항상 같이 바뀌고,
방향 모드에서는 따로 켤 수 있다 — 오른쪽 그림에서 화살표로 확인해보자.
간선 수 E는 위 에디터에서 만든 그래프를 그대로 사용한다. 정점 수 V만 슬라이더로 늘려보면서 두 저장 방식의 메모리 사용량(칸 수)이 어떻게 벌어지는지 비교해보자.
# 인접 리스트: 딕셔너리로 표현 graph_list = { 'A': ['B', 'D'], 'B': ['A', 'C'], 'C': ['B'], 'D': ['A'], } # "B와 C가 연결됐나?" → B의 리스트를 훑어야 함: O(degree) if 'C' in graph_list['B']: print('연결됨')
# 인접 행렬: 2차원 리스트로 표현 (0=A, 1=B, 2=C, 3=D) graph_matrix = [ [0, 1, 0, 1], # A: B, D 와 연결 [1, 0, 1, 0], # B: A, C 와 연결 [0, 1, 0, 0], # C: B 와 연결 [1, 0, 0, 0], # D: A 와 연결 ] # "B(1)와 C(2)가 연결됐나?" → 표 한 칸만 보면 됨: O(1) if graph_matrix[1][2] == 1: print('연결됨')
그래프는 정점 + 간선일 뿐이고, 그걸 코드로 담는 방법은 두 가지 — 인접 행렬은 조회가 빠른 대신 정점 수의 제곱만큼 자리를 차지하고, 인접 리스트는 실제 간선만큼만 쓰는 대신 조회가 느리다. 희소 그래프 + BFS/DFS류 → 리스트, 밀집 그래프 + 모든 쌍 계산(플로이드-워셜) → 행렬이 기본 선택이다.