- Graph는 Vertex(정점) 과 Edge(간선) 으로 이루어진 자료구조이다.
그래프 관련 용어
- 차수(Degree) : 정점에 연결된 간선의 수
- 인접(Adjacent) : 두 정점이 간선으로 연결되어 있는 상태
- 경로(Path) : 한 정점에서 다른 정점으로 이어지는 간선의 연속
- 사이클(Cycle) : 경로의 시작 정점과 끝 정점이 동일한 경우
- 가중치(Weight) : 간선에 할당된 가중치 값을 의미한다
- 최단 경로(Shortest Path) : 두 정점 사이의 가장 짧은 경로이다.
- 컴포넌트(Component): 그래프에서 연결된 정점들의 집합을 의미한다. 무향 그래프에서 컴포넌트는 연결 요소(Connected Component)라고도 한다.
- 이웃(Neighbor): 한 정점과 인접한 정점이다.
- 강결합(Strongly Connected): 유향 그래프에서 모든 정점 쌍이 서로 도달 가능한 상태이다.
- 약결합(Weakly Connected): 유향 그래프에서 무향 그래프와 같이 모든 정점 쌍이 서로 도달 가능한 상태이다.
- 위상 정렬(Topological Sorting): 유향 그래프에서 모든 정점을 방향성에 따라 일렬로 나열하는 것을 의미한다.
- 사이클이 존재하지 않아야 가능하다.
- 완전 그래프(Complete Graph) : 모든 정점이 서로 연결되어 있는 그래프를 의미한다.
- 정점이 n개일 때 간선의 수 = n(n-1)/2* 이다.
Directed Graph vs Undirected Graph
- 방향성에 따라 방향 그래프와 무방향 그래프로 나뉜다.
Weighted Graph vs Unweighted Graph
- 간선에 비용/가중치 할당 유무에 따라 가중치 그래프와 비가중치 그래프로 나뉜다.
스패닝 트리(Spanning Tree)
- 위 그림처럼 그래프의 모든 정점을 포함하면서 사이클이 존재하지 않는 부분 그래프를 의미한다.
- 신장 트리라고도 하며, 그래프의 최소 연결 부분 그래프이다.
- n개의 정점을 (n-1)개의 간선으로 연결한 상태이다.
그래프의 구현 방법
1. 인접 그래프(Adjacency Graph = Adjacent Matrix) 활용
- 그래프의 정점과 간선을 2차원 배열로 나타내는 방법이다.
- 장점
- 그래프의 연결 관계를 2차원 배열로 표현하기 때문에 연결 관계를 빠르게 확인할 수 있다. O(1)의 시간복잡도로 확인 가능하다.
- 각 정점의 차수를 쉽게 계산할 수 있다.
- 단점
- 정점의 개수가 많아지면 차지하는 메모리 공간이 크게 증가한다. (2차원 배열)
- 특정 정점과 연결된 모든 노드를 찾으려면 해당 배열을 전부 탐색해야 하므로 O(N)의 시간복잡도를 갖는다.
- 인접 그래프 생성
int[][] graph;
public AdjacencyMatrix(int size) {
graph = new int[size][size];
}
- 정점 연결
public void addEdge(int from, int to) {
graph[from][to] = 1;
graph[to][from] = 1; // 무향 그래프인 경우 반대 방향도 추가
}
- 정점 삭제
public void removeEdge(int from, int to) {
graph[from][to] = 0;
graph[to][from] = 0; // 무향 그래프인 경우 반대 방향도 제거
}
- 인접 그래프 출력
public void printGraph() {
for (int i = 0; i < graph.length; i++) {
for (int j = 0; j < graph[i].length; j++) {
System.out.print(graph[i][j] + " ");
}
System.out.println();
}
}
2. 인접 리스트(Adjacency List) 활용
- 그래프의 각 정점에 대해 인접한 정점들을 리스트로 나타내는 방법이다.
- 장점
- 정점의 연결 정보만을 저장하기 때문에, 정점의 개수가 많아질 경우 인접 그래프 방식보다 더 적은 메모리 공간을 차지한다.
- 특정 정점과 연결된 정점들을 찾는 경우 시간복잡도가 O(차수)로 줄어든다.
- 그래프 구조가 유동적으로 변경되는 상황이라면, 수정이 훨씬 빠르다.
- 단점
- 각 노드간 연결 상태를 확인하는데 O(N)의 시간복잡도를 갖는다.
- 인접 리스트 생성
Map<Integer, List<Integer>> graph;
public AdjacencyList() {
graph = new HashMap<>();
}
- 정점 연결
public void addEdge(int from, int to) {
//새로 추가되는 정점일 경우
if (!graph.containsKey(from)) {
graph.put(from, new ArrayList<>());
}
//from 정점과 to 정점을 연결
graph.get(from).add(to);
//to 정점이 없는 경우 새로 추가
if (!graph.containsKey(to)) {
graph.put(to, new ArrayList<>());
}
graph.get(to).add(from); // 무향 그래프인 경우 반대 방향도 추가
}
- 정점 삭제
public void removeEdge(int from, int to) {
if (graph.containsKey(from)) {
graph.get(from).remove(Integer.valueOf(to));
}
if (graph.containsKey(to)) {
graph.get(to).remove(Integer.valueOf(from)); // 무향 그래프인 경우 반대 방향도 제거
}
}
- 인접 리스트 출력
public void printGraph() {
for (Map.Entry<Integer, List<Integer>> entry : graph.entrySet()) {
System.out.print(entry.getKey() + ": ");
for (int v : entry.getValue()) {
System.out.print(v + " ");
}
System.out.println();
}
}
'Computer Science > Data Structure' 카테고리의 다른 글
Hash (0) | 2023.04.21 |
---|---|
Array / List / ArrayList / LinkedList (0) | 2023.03.16 |