그래프란?
정점(Vertex)들의 집합과 이들을 연결하는 간선 (Edge)들의 집합으로 구성된 자료구조
그래프의 종류
- 무향 그래프(Undirected Graph)
- 유향 그래프(Directed Graph)
- 순환 그래프(Cycle graph)
- 가중치 그래프(Weighted Graph)
- 사이클 없는 방향 그래프(DAG, Directed Acyclic Graph)
그래프 저장 방법
간선의 정보를 저장하는 방식, 메모리나 성능을 고려해서 결정
1. 인접 행렬
2. 인접 리스트
인접 행렬(Adjacent matrix)
|V| x |V| 크기의 2차원 배열을 이용해서 간선 정보를 저장(V: 정점의 수) 배열의 배열
인접 리스트(Adjacent List)
각 정점마다 해당 정점으로 나가는 간선의 정보를 저장
인접 행렬 | 인접 리스트 | |
A와 B를 잇는 간선 존재 여부 확인 (시간 복잡도) |
O(1) | O(min(deg(A), deg(B))) |
A와 연결된 모든 정점 확인 (시간 복잡도) |
O(|V|) | O(deg(A)) |
공간 복잡도 | O(|V|2) | O(|E|) |
그래프 탐색 방법
깊이 우선 탐색(Depth First Search)
루트 노드(시작 정점 , 출발 위치)에서 출발하여 한 방향으로 갈 수 있는 경로가 있는 곳까지 깊이 탐색해 가다가 더 이상 갈 곳이 없게 되면, 가장 마지막에 만났던 갈림길 간선이 있는 노드(정점)로 되돌아와서 다른 방향의 노드 정점 으로 탐색을 계속 반복하여 결국 모든 노드(정점)을 방문하는 순회방법
예시 코드
public class 그래프01_DFS {
static int N = 7;
//인접행렬
static int[][] adj = {
{ 0, 1, 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0, 0, 1 },
{ 1, 0, 0, 1, 0, 0, 0 },
{ 0, 1, 1, 0, 0, 0, 1 },
{ 0, 0, 0, 0, 0, 1, 1 },
{ 1, 0, 0, 0, 1, 0, 0 },
{ 0, 1, 0, 1, 1, 0, 0 } };
static boolean[] visited = new boolean[N];
public static void main(String[] args) {
DFS(0);
}
static void DFS(int v) {
// v에 대한 방문처리를 하겠다.
visited[v] = true;
System.out.println(v+1);
//나와 연결되어 있으면서 (간선이 존재하면서) 아직 방문하지 않은 정점을 재귀호출
for(int i = 0; i<N; i++) {
//방문하지 않았고 / 간선이 존재하면
if(!visited[i] && adj[v][i] == 1) {
DFS(i);
}
}
}
}
너비 우선 탐색(Breadth First Search)
너비 우선 탐색은 탐색 루트 노드(시작 정점 , 출발 위치)의 자식 노드(인접한 정점)들을 먼저 모두 차례로 방문한 후에 방문했던 자식 노드들(인접한 정점)을 시작점으로 하여 다시 해당 노드의 자식 노드(인접한 정점)들을 차례로 방문하는 방식
예시코드
import java.util.LinkedList;
import java.util.Queue;
public class BFS_01 {
static int N = 7;
//인접행렬
static int[][] adj = {
{ 0, 1, 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0, 0, 1 },
{ 1, 0, 0, 1, 0, 0, 0 },
{ 0, 1, 1, 0, 0, 0, 1 },
{ 0, 0, 0, 0, 0, 1, 1 },
{ 1, 0, 0, 0, 1, 0, 0 },
{ 0, 1, 0, 1, 1, 0, 0 } };
static boolean[] visited = new boolean[N];
static Queue<Integer> queue = new LinkedList<>();
public static void main(String[] args) {
BFS(0);
}
static void BFS(int v) {
queue.add(v);
visited[v] = true;
while (!queue.isEmpty()) {
int curr = queue.poll();
System.out.print(curr+1+" ");
for (int i = 0; i < adj.length; i++) {
if(adj[curr][i]==1 && !visited[i]) {
queue.add(i);
visited[i] = true;
}
}
}
}
}
시간 복잡도
DFS | BFS | |
인접 행렬 | O(n2) | O(n2) |
인접 리스트 | O(n+e) | O(n+e) |
예시 문제
https://www.acmicpc.net/problem/1260
1260번: DFS와 BFS
첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사
www.acmicpc.net
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
static int N, M, V;
static boolean[] visited;
static ArrayList<Integer>[] arr;
static Queue<Integer> queue = new LinkedList<>();
static StringBuilder sb = new StringBuilder();
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
V = Integer.parseInt(st.nextToken());
visited = new boolean[N+1];
arr = new ArrayList[N+1];
for (int i = 1; i <= N; i++) {
arr[i] = new ArrayList<>();
}
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int x = Integer.parseInt(st.nextToken());
int y = Integer.parseInt(st.nextToken());
arr[x].add(y);
arr[y].add(x);
}
for (int i = 1; i <= N; i++) {
Collections.sort(arr[i]);
}
DFS(V);
System.out.println(sb.toString());
sb = new StringBuilder(); Arrays.fill(visited, false);
BFS(V);
System.out.println(sb.toString());
}
// DFS 탐색
private static void DFS(int v) {
visited[v] = true;
sb.append(v).append(' ');
for (int i = 0; i < arr[v].size(); i++) {
if(visited[arr[v].get(i)]) continue;
DFS(arr[v].get(i));
}
}
// BFS 탐색
private static void BFS(int v) {
queue.add(v);
visited[v] = true;
while (!queue.isEmpty()) {
int x = queue.poll();
sb.append(x).append(' ');
for (int i = 0; i < arr[x].size(); i++) {
if(visited[arr[x].get(i)]) continue;
queue.add(arr[x].get(i));
visited[arr[x].get(i)] = true;
}
}
}
}
'알고리즘, 자료구조 > 이론' 카테고리의 다른 글
[알고리즘/JAVA] 최소 비용 신장 트리(MST) - 크루스칼, 프림 (0) | 2023.05.01 |
---|---|
[알고리즘/JAVA] 그래프 - 유니온 파인드(Union-Find) (0) | 2023.04.27 |
[알고리즘/JAVA] 트리 (0) | 2023.04.12 |
[알고리즘/JAVA] 완전탐색 - 백트래킹 (0) | 2023.04.08 |
[알고리즘/JAVA] 자료구조 - 시간복잡도(queue, stack, arraylist, linkedlist) (0) | 2023.04.02 |