탐색 - 6. 그래프 탐색 개요 (Graph Search)
2025. 2. 24. 14:57ㆍ소프트웨어/알고리즘
📌 6. 그래프 탐색 개요 (Graph Search)
6.1 그래프(Graph)란?
🔹 그래프의 개념
그래프(Graph)는 정점(Vertex, Node)과 간선(Edge)으로 이루어진 자료구조로, 다양한 연결 관계를 표현하는 데 사용됩니다.
💡 그래프의 활용 예시
- 소셜 네트워크 → 친구 관계(정점: 사람, 간선: 친구 관계)
- 지도와 길 찾기 → 도시 간 최단 경로(정점: 도시, 간선: 도로)
- 웹 크롤링 → 웹페이지 간의 연결(정점: 웹페이지, 간선: 하이퍼링크)
- 컴퓨터 네트워크 → 라우터 간 연결 구조
🔹 그래프의 구성 요소
- 정점(Vertex, Node): 데이터를 저장하는 요소
- 간선(Edge): 정점 간의 연결 관계
- 가중치(Weight, 선택적): 간선에 부여된 값 (예: 도로 거리, 비용)
- 방향성(Directionality)
- 무방향 그래프 (Undirected Graph): 양방향 이동 가능
- 방향 그래프 (Directed Graph, DAG): 한쪽 방향으로만 이동 가능
6.2 인접 행렬(Adjacency Matrix)과 인접 리스트(Adjacency List) 소개
🔹 1) 인접 행렬 (Adjacency Matrix)
- 2차원 배열을 사용하여 그래프를 표현하는 방법
- matrix[i][j] = 1 → i번 정점에서 j번 정점으로 이동 가능
- 공간 복잡도: O(V²) (V는 정점의 개수)
- 빠른 연결 확인: O(1) (임의의 두 정점이 연결되었는지 확인 가능)
- 메모리 낭비 가능: 간선이 적은 경우(희소 그래프) 불필요한 0이 많음
✔ 적합한 경우: 그래프가 빽빽하게 연결된 경우(완전 그래프)
🔹 2) 인접 리스트 (Adjacency List)
- 연결 리스트(Linked List)를 사용하여 그래프를 표현하는 방법
- list[i]는 i번 정점과 연결된 정점들의 리스트를 저장
- 공간 복잡도: O(V + E) (E는 간선의 개수)
- 빠른 간선 추가: 새로운 간선 추가 시 O(1) 가능
- 느린 연결 확인: 특정 간선이 존재하는지 확인하려면 O(V) 필요
✔ 적합한 경우: 간선이 적은 경우(희소 그래프)
6.3 깊이 우선 탐색(DFS) vs 너비 우선 탐색(BFS)의 차이점
탐색 방식 | 동작 방식 | 사용 자료구조 | 시간 복잡도 | 특징 |
DFS (Depth First Search) | 한 방향으로 끝까지 탐색 후 되돌아감 (백트래킹) | 스택(Stack) / 재귀(Recursive) | O(V + E) | 미로 찾기, 백트래킹 |
BFS (Breadth First Search) | 가까운 정점부터 차례대로 탐색 | 큐(Queue) | O(V + E) | 최단 경로 탐색 |
💡 언제 DFS/BFS를 사용해야 할까?
- DFS → 모든 경로 탐색이 필요할 때 (예: 미로 탐색, 백트래킹)
- BFS → 최단 경로 탐색이 필요할 때 (예: 길 찾기, 네트워크 거리 계산)
🔍 실습: 인접 행렬과 인접 리스트를 사용하여 그래프 구현
1️⃣ 인접 행렬 (Adjacency Matrix) 구현
#include <stdio.h>
#define V 5 // 정점 개수
// 그래프 출력 함수
void printGraph(int graph[V][V]) {
printf("인접 행렬 그래프 표현:\n");
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
printf("%d ", graph[i][j]);
}
printf("\n");
}
}
int main() {
// 5개의 정점을 가진 그래프 초기화
int graph[V][V] = { {0, 1, 1, 0, 0},
{1, 0, 0, 1, 0},
{1, 0, 0, 1, 1},
{0, 1, 1, 0, 1},
{0, 0, 1, 1, 0} };
printGraph(graph);
return 0;
}
📌 실행 결과
인접 행렬 그래프 표현:
0 1 1 0 0
1 0 0 1 0
1 0 0 1 1
0 1 1 0 1
0 0 1 1 0
2️⃣ 인접 리스트 (Adjacency List) 구현
#include <stdio.h>
#include <stdlib.h>
#define V 5 // 정점 개수
// 연결 리스트 노드 구조체
typedef struct Node {
int vertex;
struct Node* next;
} Node;
// 그래프 구조체
typedef struct {
Node* head[V]; // 정점별 인접 리스트
} Graph;
// 그래프 초기화
Graph* createGraph() {
Graph* graph = (Graph*)malloc(sizeof(Graph));
for (int i = 0; i < V; i++) {
graph->head[i] = NULL;
}
return graph;
}
// 간선 추가 (양방향 그래프)
void addEdge(Graph* graph, int src, int dest) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->vertex = dest;
newNode->next = graph->head[src];
graph->head[src] = newNode;
// 반대 방향도 추가 (무방향 그래프)
newNode = (Node*)malloc(sizeof(Node));
newNode->vertex = src;
newNode->next = graph->head[dest];
graph->head[dest] = newNode;
}
// 그래프 출력
void printGraph(Graph* graph) {
for (int i = 0; i < V; i++) {
printf("정점 %d: ", i);
Node* temp = graph->head[i];
while (temp) {
printf("%d -> ", temp->vertex);
temp = temp->next;
}
printf("NULL\n");
}
}
// 메모리 해제
void freeGraph(Graph* graph) {
for (int i = 0; i < V; i++) {
Node* temp = graph->head[i];
while (temp) {
Node* prev = temp;
temp = temp->next;
free(prev);
}
}
free(graph);
}
int main() {
Graph* graph = createGraph();
addEdge(graph, 0, 1);
addEdge(graph, 0, 2);
addEdge(graph, 1, 3);
addEdge(graph, 2, 3);
addEdge(graph, 2, 4);
addEdge(graph, 3, 4);
printGraph(graph);
freeGraph(graph);
return 0;
}
📌 실행 결과
정점 0: 2 -> 1 -> NULL
정점 1: 3 -> 0 -> NULL
정점 2: 4 -> 3 -> 0 -> NULL
정점 3: 4 -> 2 -> 1 -> NULL
정점 4: 3 -> 2 -> NULL
📌 마무리 및 정리
- 그래프(Graph): 정점(Vertex)과 간선(Edge)으로 이루어진 자료구조
- 그래프 표현 방식
- 인접 행렬 → 빠른 연결 확인, O(V²) 공간 복잡도
- 인접 리스트 → 적은 메모리 사용, O(V + E) 공간 복잡도
- DFS vs BFS
- DFS: 백트래킹, 미로 찾기, 깊이 있는 탐색
- BFS: 최단 경로 탐색, 네트워크 분석
'소프트웨어 > 알고리즘' 카테고리의 다른 글
탐색 - 8. 너비 우선 탐색(BFS, Breadth First Search) (0) | 2025.02.24 |
---|---|
탐색 - 7. 깊이 우선 탐색(DFS, Depth First Search) (0) | 2025.02.24 |
탐색 - 5. 해싱(Hashing) 기법 (0) | 2025.02.24 |
탐색 - 4. 점프 탐색(Jump Search) & 보간 탐색(Interpolation Search) (0) | 2025.02.24 |
탐색 - 3. 이진 탐색(Binary Search) (0) | 2025.02.24 |