그래프
개념
- 단순히(node, N)와 그 노드를 연결하는 간선(edge, E)을 하나로 모아 놓은 자료구조
- 연결되어 있는 객체 간의 관계를 표현할 수 있는 자료구조
용어
- 정점(vertex): 위치라는 개념. (node 라고도 부름)
- 간선(edge): 위치 간의 관계. 즉, 노드를 연결하는 선 (link, branch 라고도 부름)
- 인접 정점(adjacent vertex): 간선에 의 해 직접 연결된 정점
- 정점의 차수(degree): 무방향 그래프에서 하나의 정점에 인접한 정점의 수
- 무방향 그래프에 존재하는 정점의 모든 차수의 합 = 그래프의 간선 수의 2배
- 진입 차수(in-degree): 방향 그래프에서 외부에서 오는 간선의 수 (내차수 라고도 부름)
- 진출 차수(out-degree): 방향 그래픙에서 외부로 향하는 간선의 수 (외차수 라고도 부름)
- 방향 그래프에 있는 정점의 진입 차수 또는 진출 차수의 합 = 방향 그래프의 간선의 수(내차수 + 외차수)
- 경로 길이(path length): 경로를 구성하는 데 사용된 간선의 수
- 단순 경로(simple path): 경로 중에서 반복되는 정점이 없는 경우
- 사이클(cycle): 단순 경로의 시작 정점과 종료 정점이 동일한 경우
특징
- 그래프는 네트워크 모델이다.
- 2개 이상의 경로가 가능하다.
- 즉, 노드들 사이에 무방향/방향에서 양방향 경로를 가질 수 있다.
- self-loop 뿐 아니라 loop/circuit 모두 가능하다.
- 루트 노드라는 개념이 없다.
- 부모-자식 관계라는 개념이 없다.
- 순회는 DFS나 BFS로 이루어진다.
- 그래프는 순환(Cyclic) 혹은 비순환(Acyclic)이다.
- 그래프는 크게 방향 그래프와 무방향 그래프가 있다.
- 간선의 유무는 그래프에 따라 다르다.
- 해당 자료구조는 그래프 구조와 그래프 관리에 사용되는 알고리즘에 영향을 받는다.
- 이론적으로 그래프는 리스트와 행렬 구조 중의 하나로 구별 가능하지만, 실제 적용에 있어서 최적의 자료구조는 두 구조의 조합된 형태를 띤다.
종류
- 무방향 그래프 & 방향 그래프
- 가중치 그래프(Weighted Graph)
- 연결 그래프 & 비연결 그래프
- 사이클(Cycle) & 비순환 그래프(Acyclic Graph)
- 완전 그래프(Complete Graph)
구현방법 2가지
인접 리스트(Adjacency List)
- 모든 정점(vertex) 및 노드(Node)를 리스트(ArrayList, LinkedList)에 저장. 즉, 각각의 노드에 인접한 노드들을 저장
- 정점 index를 통해 각 노드에 인접한 노드 리스트를 확인할 수 있다.
- 무방향 그래프에서는 간선이 인접한 노드에 모두 저장되기 때문에 두번 저장된다.
ex) 정점의 수: N, 간선의 수:E인 무방향 그래프인 경우
N개의 리스트, N개의 배열, 2E개의 노드가 필요
인접 배열(Adjacency Matrix)
- 정점 혹은 노드의 개수가 N인 그래프를 인접 행렬로 표현
- 간선의 수와 무관하게 항상 n^2개의 메모리 공간이 필요
- 무방향 그래프를 인접 행렬로 표현한다면, 대칭 행렬이 된다.
- 인접 리스트의 경우 인접한 노드의 리스트를 갖고 있기 때문에 인접한 노드를 쉽게 찾을 수 있지만, 인접 행렬에서는 인접한 노드를 찾기 위해서는 모든 노드를 전부 순회해야 한다.
인접 리스트와 인접 행렬의 용도 차이
- 인접 리스트
- 그래프 내에 적은 숫자의 간선만을 갖는 희소 그래프(Sparse Graph)인 경우
- 어떤 노드에 인접한 노드를 찾는 경우
- 단, 간선의 존재 여부와 정점의 차수: 정점 i의 리스트에 있는 도드의 수, 즉 정점 차수만큼의 시간이 필요
- 인접 행렬
- 그래프에 간선이 많이 존재하는 밀집 그래프(Dense Graph)의 경우
- 두 정점을 연결하는 간선의 존재여부(M[i][j])를 O(1)안에 즉시 알 수 있다.
- 정점의 차수는 O(N)안에 알 수 있다. (인접 배열의 i번 째 행 또는 열을 모두 더한다.)
- 단, 어떤 노드에 인접한 노드들을 찾기 위해서는 모든 노드를 전부 순회해야한다.
- 그래프에 존재하는 모든 간선의 수는 O(n^2) 안에 알 수 있다. (인접 행렬 전체를 검색)
- 인접 리스트
코드 설계
- 루트에서 시작한다.
- 자식 노드들을 [1]에 저장한다.
- [1]에 저장된 노드들을 차례로 방문한다. 또한 각각의 자식들을 [2]에 저장한다.
- [2]에 저장된 노드들을 차례로 방문한다. 또한 각각의 자식들을 [3]에 저장한다.
- 위의 과정을 반복한다.
- 모든 노드를 방문하면 탐색을 마친다.
코드 구현
- 행렬로 구현한 그래프 (인접행렬)
public class Graph {
private int[][] MATRIX; // 그래프 배열 선언
public Graph() {}
public Graph(int initSize) {
this.MATRIX = new int[initSize + 1][initSize + 1];
}
public void put(int x, int y) {
MATRIX[x][y] = MATRIX[y][x] = 1;
}
public void printGraph() {
for (int i = 0; i < MATRIX.length; i++) {
for (int j = 0; j < MATRIX[i].length; j++) {
System.out.print(MATRIX[i][j] + " ");
}
System.out.println();
}
}
}
- 리스트로 구현한 그래프 (인접 리스트)
public class Graph {
private int V;
private LinkedList<Integer>[] adjacent;
public Graph(int V) {
this.V = V;
this.adjacent = new LinkedList[V];
for (int i = 0; i < V; i++) adjacent[i] = new LinkedList<>();
}
public void addEdge(Graph graph, int src, int dest) {
graph.adjacent[src].add(dest);
graph.adjacent[dest].add(src);
}
public void printGraph(Graph graph) {
for (int v = 0; v < graph.V; v++) {
System.out.println("Adjacency list of vertex " + v);
System.out.print("head");
for (Integer pCrawl : graph.adjacent[v]) {
System.out.print(" -> " + pCrawl);
}
System.out.println("\n");
}
}
}
'알고리즘&자료구조 > basic' 카테고리의 다른 글
[알고리즘] 깊이 우선 탐색(Deap First Search, DFS) (0) | 2020.05.15 |
---|---|
[알고리즘] 너비 우선 탐색(Breadth First Search, BFS) (0) | 2020.05.13 |
[자료구조] 트리(Tree) (0) | 2020.05.12 |
[자료구조] 큐(Queue) (0) | 2020.05.12 |
[자료구조] 스택(Stack) (0) | 2020.05.10 |