그래프는 두 가지 표현 방식이 있다.
인접 행렬 방식
인접 행렬 방식은 행렬 개념의 표를 이용해 표현하는 방식이다.
1번 노드에서 3번 노드로 가는 간선이 있다면 2차원 배열을 선언하고 1행 3열에 해당하는 칸에 1(true)값을 저장하는 방식이다.
아래에서 설명할 무방향 그래프의 경우 1번 노드에서 3번노드로 가는 간선이 있다면 당연히 3번 노드에서 1번노드로 가는 간선도 존재하는 것이기 때문에 대칭 행렬이 그려지게 된다.
하지만, 방향 그래프의 경우 대칭되지않는 경우도 존재 할 수 있다.
또 가중치가 존재하는 그래프에선 행렬에 1(true), 0(false) 값이 아닌 가중치가 저장된다.

인접 리스트 방식
간선의 연결정보만을 가지고 자료 구조의 기본이되는 연결리스트처럼 1번노드가 자신과 연결된 다음 노드의 주소값을 가지고 있는 형태로 구현하는 방식이다.

보기 편하게 분해해 놓은 그림이다. 그림과는 조금다르게
→ B ( B로 가는간선 이라는 의미)
B ⇒ {→ A, → C, → E} (B는 A로가는 간선, C로 가는 간선, E로 가는 간선을 가진다는 의미)
위 와 같은 형태로 표현된다.

방향성을 띄는 간선을 가진 그래프이다. 그래프 탐색을 진행할 때 방향성의 반대로는 탐색 하지 못한다.
알파벳을 각각 A-1, B-2 이런식으로 가정한다.
또 0번 노드는 취급 하지 않아서 배열의 크기가 (전체 노드 개수 + 1)^2 이다.
//전체 노드 개수
int nodeCnt = 6;
// 그래프의 간선정보(대개 하위로 내려가는 방향으로만 주어짐
// {5,4}는 역방향만 존재 하므로 예외)
int[][] edgeInfo = new int[][]{{1,2},{2,3},{2,5},{3,4},{3,5},{5,4},{5,6}};
// 인접 행열 방식의 그래프
int[][] graph = new int[nodeCnt+1][nodeCnt+1];
for(int i = 0; i < edgeInfo.length; i++) {
graph[edgeInfo[i][0]][edgeInfo[i][1]] = 1;
}
//출력
/*
\ 0 1 2 3 4 5 6
0 0, 0, 0, 0, 0, 0, 0
1 0, 0, 1, 0, 0, 0, 0
2 0, 0, 0, 1, 0, 1, 0
3 0, 0, 0, 0, 1, 1, 0
4 0, 0, 0, 0, 0, 0, 0
5 0, 0, 0, 0, 1, 0, 1
6 0, 0, 0, 0, 0, 0, 0
*/

방향 상관없이 탐색할 수 있다 구현할때는 두 가지 방향 다 탐색이 가능하게 구현해야한다는 의미 이다.
//전체 노드 개수
int nodeCnt = 6;
// 그래프의 간선정보(대개 하위로 내려가는 방향으로만 주어짐)
int[][] edgeInfo = new int[][]{{1,2},{2,3},{2,5},{3,4},{3,5},{4,5},{5,6}};
// 인접 행열 방식의 그래프
int[][] graph = new int[nodeCnt+1][nodeCnt+1];
for(int i = 0; i < edgeInfo.length; i++) {
graph[edgeInfo[i][0]][edgeInfo[i][1]] = 1;
graph[edgeInfo[i][1]][edgeInfo[i][0]] = 1;
}
//출력
/*
\ 0 1 2 3 4 5 6
0 0, 0, 0, 0, 0, 0, 0
1 0, 0, 1, 0, 0, 0, 0
2 0, 1, 0, 1, 0, 1, 0
3 0, 0, 1, 0, 1, 1, 0
4 0, 0, 0, 1, 0, 1, 0
5 0, 0, 1, 1, 1, 0, 1
6 0, 0, 0, 0, 0, 1, 0
*/

간선에 가중치가 존재하고 그래프의 탐색을 결정하는 요소에 가중치의 최소값을 선택해서 탐색하는 조건이 추가될 수 있다.
가중치 그래프를 쉽게 이해하는 방법은 가중치를 노드간 이동에 소요되는 시간이라고 생각하면 쉽게 이해할 수 있다.
A → B : A노드에서 B노드로 이동하는 데에는 3분이라는 시간이 소요된다.
이 와 같은 개념을 가진 상태로 가중치 방향, 무방향 그래프도 이해해보자
이번 파트는 가중치에 대해 설명하는 파트로 가중치라는 개념에 중점을 둬서 위와 같은 결론이 나오는 것이고 최소 노드 수를 우선으로 하는 탐색 조건이라면 위의 설명과 결론이 다를 수 있다. 하지만 대부분 가중치를 가진 그래프가 주어지는 상황에선 가중치가 가장 우선적인 탐색 조건으로 적용된다.
관련 알고리즘으로는 최소 비용 신장 트리 알고리즘(minimum spanning tree, MST)이 있다.
//전체 노드 개수
int nodeCnt = 6;
// 그래프의 간선정보(대개 하위로 내려가는 방향으로만 주어짐)
// {startNode, endNode, weight}
int[][] edgeInfo = new int[][]{{1,2,3},{2,3,4},{2,5,20},{3,4,9},{3,5,2},{4,5,1},{5,6,10}};
// 인접 행열 방식의 그래프
int[][] graph = new int[nodeCnt+1][nodeCnt+1];
for(int i = 0; i < edgeInfo.length; i++)
graph[edgeInfo[i][0]][edgeInfo[i][1]] = edgeInfo[i][2];
graph[edgeInfo[i][1]][edgeInfo[i][0]] = edgeInfo[i][2];
}
//출력
/*
\ 0 1 2 3 4 5 6
0 0, 0, 0, 0, 0, 0, 0
1 0, 0, 3, 0, 0, 0, 0
2 0, 3, 0, 4, 0, 20, 0
3 0, 0, 4, 0, 9, 2, 0
4 0, 0, 0, 9, 0, 1, 0
5 0, 0, 20, 2, 1, 0, 10
6 0, 0, 0, 0, 0, 10, 0
*/

트리는 그래프에서 포함된 개념이다.
실질적으로는 방향이 존재하는 방향 그래프에 속 하지만 루트노드에서 리프노드를 향하는 단방향 방향성을 가지므로 방향성 표현이 생략 되었다. 하나의 Indegree와 여려개의 Out-degreefh 이루어져 있다.
노드, 간선, In,Out-degree는 그래프와 똑같다.
A는 1번 노드 , B는 2번 노드와같은 방식으로 숫자로 치환해서 표현함
//전체 노드 개수
int nodeCnt = 10;
// 트리의 간선 정보
int[][] edgeInfo = new int[][]{{1,2},{1,3},{2,4},{2,5},{3,6},{3,7},{4,8},{4,9},{5,10}};
// 인접 행열 방식의 그래프
int[][] tree = new int[nodeCnt+1][nodeCnt+1];
for(int i = 0; i < edgeInfo.length; i++)
tree[edgeInfo[i][0]][edgeInfo[i][1]] = 1;
}
//출력
/*
\ 0 1 2 3 4 5 6 7 8 9 10
0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0
2 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0
3 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0
4 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0
5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
10 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
*/
인접 행렬은 낭비 되는 공간이 많아서 규모가 커지면 인접 리스트로 구현하는것이 효율적이다.
// 전체 노드 개
int nodeCnt = 10;
// 트리의 간선 정보
int[][] edgeInfo = new int[][]{{1,2},{1,3},{2,4},{2,5},{3,6},{3,7},{4,8},{4,9},{5,10}};
ArrayList<Integer>[] tree = new ArrayList[nodeCnt+1];
for(int i = 1; i <= nodeCnt; i++) {
tree[i] = (new ArrayList<Integer>());
}
for(int i = 0; i < edgeInfo.length; i++) {
tree[edgeInfo[i][0]].add(edgeInfo[i][1]);
}
/*
0
1 {2,3}, 2 {4,5}, 3 {6,7}, 4 {8,9}, 5 {10}
6 {}, 7 {}, 8 {}, 9 {}, 10 {}
*/
좋은 글 감사합니다.