
Graph(그래프)
정점(vertex)와 간선(edge)으로 구성된 자료 구조로 객체 간의 관계를 표현하는데 사용된다.
구성요소
정점 : 객체(데이터)를 저장하는 노드
간선 : 객체 간의 관계, 두 정점 간의 연결선
사용 예시 : 소셜 네트워크, 지도, 컴퓨터 네트워크
그래프의 종류
- 방향 그래프
간선에 방향이 있어 A > B는 가능하지만 B > A는 별도로 정의해야 한다
ex : 웹 페이지 링크, 종속성 관계
종속성 관계란 의존성을 의미한다 하나의 노드가 다른 하나의 노드에 의존하거나 영향을 받는 관계를 나타낼 때 사용한다.
ex : 작업 A를 완료해야 B를 시작, 모듈 A가 모듈 B를 참조할 때(B가 없으면 A가 동작하지 않음), 어떤 과목을 학습할 때 다른 과목의 선행학습(기초 수학 > 미적분 > 공학 수학) - 무방향 그래프
간선에 방향이 없어 A - B는 양방향으로 연결된다
ex : SNS의 맞팔로우 - 가중치 그래프
간선에 가중치가 부여된 그래프
가중치 : 비용, 거리, 시간 등
ex : 택시요금, 자동차를 타고 이동 시 거리에 비례하여 걸리는 시간 - 비가중치 그래프
간선에 가중치가 없는 그래프
ex : 단순 연결 구조
트리와 그래프의 차이점
트리
- 계층적 구조를 가진 방향 그래프의 특수한 형태
- 항상 부모 > 자식으로 방향성이 정해져 있음
- 시작점인 루트 노드에 모든 노드가 연결됨
- 순환 구조 불가능
- ex : 계층 구조 표현(디렉토리 구조)
그래프
- 네트워크 구조로 표현되는 일반적인 데이터 구조
- 간선에 방향이 있을 수도 없을 수도 있음
- 반드시 계층이 요구되지 않음
- 순환 구조 가능
- ex : 사람들 간의 친구 관계(A와 B는 서로를 모르지만 C는 서로를 알고 있다, C는 D도 알고 있다
그래프의 표현 방식
Adjacency Matrix(인접 행렬)
- 그래프를 2차원 배열로 표현하는 방식
- 행과 열이 그래프의 정점(vertex)를 나타냄
- 특정한 두 정점 간에 간선(edge)이 존재하면 해당 위치에 값을 기록
값의 의미
- 0 or false : 두 정점 사이에 간선이 없음
- 1 또는 가중치 : 두 정점 사이에 간선이 있음 (가중치 그래프에서는 간선 값의 가중치를 저장)
ex:
| A | B | C | |
| A | 0 | 1 | 1 |
| B | 1 | 0 | 0 |
| C | 0 | 1 | 0 |
장점
- 간선 존재 여부를 빠르게 확인 가능 O(1)
- 구현이 간단하고 메모리에서 정적으로 관리
단점
- 간선이 적은 희소 그래프에서 많은 공간을 낭비
- 모든 인접 노드 순회 시간은 O(V) : 모든 정점을 확인해야함
Adjacency List(인접리스트)
- 그래프를 연결리스트 또는 배열의 리스트 형태로 표현
- 각 정점에 대해 연결된 다른 정점들의 리스트를 저장
구조
- 리스트는 노드마다 동적으로 생성되고, 연결된 정점만 포함
- 메모리를 간선 개수에 비례하여 사용
ex
A : B, C
B : A, D
C : A
D : B
장점
- 효율적인 메모리 사용 : 간선이 적은 경우 공간 낭비가 적음
- 인접노드 순회 시간 : 연결된 노드만 확인 O(K) k : 간선수
단점
- 간선 존재 여부 확인이 느림 : 특정 간선이 있는지 확인하는데 O(K)
- 구현이 복잡
희소 그래프와 밀집 그래프
간선의 수에 따라 희소 그래프와 밀집 그래프로 나눈다
희소 그래프
- 간선의 수가 적음
- 일반적으로 E << V의 제곱 (간선 E의 수가 정점 V의 제곱보다 훨씬 적음)
- 간선 밀도가 낮다
- 인접 리스트로 표현(효율적인 메모리 사용)
밀집 그래프
- 간선의 수가 상대적으로 많음
- 일반적으로 E ≈ V의 제곱(간선 E의 수가 정점 V의 제곱에 가까움)
- 간선 밀도가 높음
- 인접 행렬을 사용 간선 존재 여부를 빠르게 확인하고 간선 수가 많아 메모리 낭비가 적음
간선의 밀도
- 간선 밀도의 계산은 E/V의 제곱으로 계산
- 밀도가 0에 가까우면 희소, 1에 가까우면 밀집그래프
그래프의 탐색 알고리즘
DFS(Depth-First Search)
깊이 우선 탐색으로 그래프의 한 경로를 따라 갈 수 있을 만큼 깊이 탐색한 뒤 갈 곳이 없으면 되돌아와 다른 경로를 탐색하는 방식
구현 방법
- 재귀 : 재귀 호출을 사용하여 스택 동작을 구현
- 스택 : 명시적으로 스택을 사용
동작 과정
- 시작 노드에서 출발
- 연결된 노드를 따라 깊이 탐색
- 탐색할 곳이 없으면 되돌아와 새로운 경로 탐색
- 시간 복잡도 : O(V+E)
- 메모리 사용 적음
- 경로 찾기(미로 탐색 등)
- 사이클 검사 : 그래프가 순환인지 확인
BFS(Breadth-First Search)
너비 우선 탐색으로 시작 노드에서 가까운 노드를 먼저 모두 방문한 뒤, 그 다음 레벨의 노드들을 차례대로 방문하는 방식
구현방법
큐(Queue) : 방문할 노드를 큐에 추가하고, 큐에서 노드를 꺼내며 탐색
동작 과정
- 시작 노드에 큐를 넣음
- 큐에서 노드를 꺼내고 방문하지 않은 이웃 노드들을 큐에 추가
- 큐가 빌때까지 반복
- 시간 복잡도 : O(V+E)
- 메모리 사용 많음
- 최단 거리 탐색
- 특정 깊이 노드 탐색
DFS와 BFS의 차이
- DFS는 스택 또는 재귀를 사용 깊이 우선 탐색
- BFS는 큐를 이용 너비 우선 탐색
- DFS는 경로를 따라가며, BFS는 계층적으로 탐색
그래프가 연결 그래프인지 확인하는 방법
- DFS 또는 BFS를 수행하여 모든 정점을 방문했는지 확인한다
그래프에서 사이클을 탐지하는 방법
- DFS를 수행하여 방문 중인 노드가 이미 방문된 노드라면 사이클이 존재한다
그래프 구현
Adjacency Matrix(인접 행렬)
https://github.com/9mans/Graph-Practice/blob/master/src/AdjacencyMatrix.java
Adjacency List(인접 리스트)
https://github.com/9mans/Graph-Practice/blob/master/src/AdjacencyList.java
DFS
https://github.com/9mans/Graph-Practice/blob/master/src/DFS.java
BFS
https://github.com/9mans/Graph-Practice/blob/master/src/BFS.java
'Data structure' 카테고리의 다른 글
| [Data Structure] Heap(힙) (0) | 2025.01.20 |
|---|---|
| [Data Structure] Binary Search Tree(이진 탐색 트리) (2) | 2025.01.20 |
| CS 자료구조 B-Tree와 B+Tree (0) | 2024.10.10 |
| CS 자료구조 Trie(트라이) (1) | 2024.10.09 |
| [자료구조] Hash(해시), Hash Table, HashMap (2) | 2024.10.08 |