그래프의 개념
단순히 노드(N,node)와 그 노드를 연결하는 간선(E,edge)을 하나로 모아놓은 자료 구조
- 즉, 연결되어 있는 개체 간의 관계를 표현할 수 있는 자료구조이다.
* ex) 지도, 지하철 노선도의 최단 경로, 전기회로의 소자들, 도로(교차점과 일방통행 길), 선수과목 등
- 그래프는 여러개의 고립된 부분 그래프(isolated Subgraphs)로 구성될 수 있다.
- 그래프는 여러개의 고립된 부분 그래프(Isolated Subgraphs)로 구성될 수 있다.
오일러 경로 (Eulerian tour)
그래프에 존재하는 모든 간선(edgd)을 한번만 통과하면서 처음 정점(vertex)으로 되돌아오게 하는 경로를 말한다.
그래프의 모든 정점에 연결된 간선의 개수가 짝수 일 때만 오일러 경로가 존재한다.
그래프와 관련된 용어
- 정점(vertex) : 위치라는 개념. (node 라고도 부름)
- 간선(edge) : 위치 간의 관계. 즉, 노드를 연결하는 선(link, branch 라고도 부름)
- 인접 정점(adjacent vertex) : 간선에 의해 직접 연결된 정점
- 정점의 차수(degree) : 무방향 그래프에서 하나의 정점에 인접한 정점의 수
* 무방향 그래프에 존재하는 정점의 모든 차수의 합 = 그래프 간선 수의 2배
- 진입 차수(in-degree) : 방향 그래프에서 외부에서 오는 간선의 수 (내차수 라고도 부름)
- 진출 차수(out-degree) : 방향 그래프에서 외부로 향하는 간선의 수 (외차수 라고도 부름)
* 방향 그래프에 있는 정점의 진입 차수 또는 진출 차수의 합 = 방향 그래프의 간선의 수(내차수 + 외차수)
- 정점 u로부터 정점 v까지의 경로(path)
* 그래프 G에서 (u,i1),(i1,i2),....,(ik,v)를 E(G)에 속한 간선들이라고 할때, 정점의 순서인 u,i1,i2,..ik,v를 말함
- 경로 길이(path length) : 경로를 구성하는데 사용된 간선의 수
- 단순 경로(simple path) : 경로 중에서 반복되는 정점이 없는 경우, 경로 상에서 처음과 마지막을 제외한 모든 정점들이 서로 다름.
- 사이클(cycle) : 처음과 마지막 정점이 같은 단순 경로
그래프의 특징
- 그래프는 네트워크 모델 이다.
- 2개 이상의 경로가 가능하다.
* 즉, 노드들 사이에 무방향/방향에서 양방향 경로를 가질 수 이싿.
- self-loop 뿐 아니라 loop/circuit 모두 가능하다.
- 루느 노드라는 개념이 없다.
- 부모-자식 관계라는 개념이 없다
- 순회는 DFS나 BFS로 이루어진다.
- 그래프는 순환(cyclic) 혹은 비순환(acyclic)이다.
- 그래프는 크게 방향 그래프와 무방향 그래프가 있다.
- 간선의 유무는 그래프에 따라 다르다.
그래프의 종류
무방향 그래프 vs 방향 그래프
- 무방향 그래프(Undirected Graph)
* 무방향 그래프의 간선은 간선을 통해서 양 방향으로 갈 수 있다.
- 정점 A와 정점 B를 연결하는 간선은(A,B)와 같이 정점의 쌍으로 표현한다.
- 방향 그래프(Directed Graph)
간선에 방향성이 존재하는 그래프
정점의 쌍 <u,v>로 표시 (u는 꼬리 tail, v는 머리 head)
A->B로만 갈 수 있는 간선은 <A,B> 로 표시한다.
<A,B>와 <B,A>는 다름
EX) 일방통행
강력 연결(strongly connected)
방향 그래프 V(G) 에 속한 서로 다른 두 정점 u,v의 모든 쌍에 대하여, u에서 v로, 또한 v에서 u로의 방향 경로(directed path)가 존재.
강력 연결 요소(strongly connected component)
* 강하게 연결된 최대 부분 그래프
가중치 그래프
- 가중치 그래프(Weighted Graph)
* 간선에 비용이나 가중치가 할당된 그래프
- '네트워크(Network)' 라고도 한다
- ex) 도시- 도시의 연결, 도로의 길이, 회로 소자의 용량, 통신망의 사용료 등
- 인접 행렬 : 행렬 엔트리에 a[i][j]의 가중치 정보 저장
- 인접 리스트 : 노드 구조에 weight 필드를 추가
연결 그래프 vs 비연결 그래프
- 연결 그래프(Connected Graph)
무방향 그래프에 있는 모든 정점 쌍에 대해서 항상 경로가 존재하는 경우
ex) 트리(Tree) : 사이클을 가지지 않는 연결 그래프
- 비연결 그래프(Disconnected Graph)
* 무방향 그래프에서 특정 정점 쌍 사이에 경로가 존재하지 않는 경우
사이클 vs 비순환 그래프
- 사이클(cycle)
단순 경로의 시작 정점과 종료 정점이 동일한 경우
단순 경로(Simple Path) : 경로 중에서 반복되는 정점이 없는 경우
- 비순환 그래프(Acyclic Graph)
* 사이클이 없는 그래프
완전 그래프
- 완전 그래프(Complete Graph)
* 그래프에 속해있는 모든 정점이 서로 연결되어 있는 그래프
- 무방향 완전 그래프
- 정점 수 : n이면 간선의 수: n*(n-1)/2
그래프의 구현
1. 인접 행렬(Adjacency Matrix)
인접 행렬은 NxN 불린 행렬(Boolean Matrix)로써 matrix[i][j]가 true라면 i->j로의 간선이 있다는 뜻이다.
- G=(V,E)는 정점의 수가 n(n>=1)인 그래프
- 인접행렬 : nxn의 2차원 배열
- 0과 1을 이용한 정수 행렬(integer matrix)을 사용할 수도 있다.
- 인접행렬의 수행시간 최소 O(n^2)
if(간선 (i, j)가 그래프에 존재)
matrix[i][j] = 1;
else
matrix[i][j] = 0;
- 정점(노드)의 개수가 N인 그래프를 인접 행렬로 표현
* 간선의 수와 무관하게 항상 n^2의 메모리 공간이 필요하다.
- 무방향 그래프를 인접 행렬로 표현한다면 이 행렬은 대칭행렬(Symmetric Matirx)이 된다.
* 물론 방향 그래프는 대칭 행렬이 안 될 수도 있다.
- 방향 그래프 : 행의 합은 진출 차수, 열의 합은 진입 차수
- 인접 리스트를 사용한 그래프 알고리즘들(ex. 너비우선탐색) 또한 인접 행렬에서도 사용 가능하다.
* 하지만 인접행렬은 효율성이 조금 떨어진다.
- 인접 리스트는 어떤 노드에 인접한 노드들을 쉽게 찾을 수 있지만, 인접 행렬에서는 인접한 노드를 찾기 위해서는 모든 노드를 전부 순회해야 한다.
2. 인접 리스트 (Adjacency Lists)
인접리스트로 그래프를 표현하는 것이 가장 일반적인 방법 이다.
- 모든 정점(혹은 노드)을 인접 리스트에 저장한다. 즉, 각각의 정점에 인접한 정점들을 리스트로 표시한 것이다.
- 배열(혹은 해시테이블)과 배열의 각 인덱스마다 존재하는 또 다른 리스트(배열, 동적 가변 크기 배열, 연결리스트 등)을 이용해서 인접 리스트를 표현
- 정점의 번호만 알면 이 번호를 배열의 인덱스로 하여 각 정점의 리스트에 쉽게 접근할 수 있다.
- 무방향 그래프(Undirected Graph)에서 (a,b) 간선은 두 번 저장된다.
- 한번은 a 정점에 인접한 간선을 저장하고, 다른 한번은 b에 인접한 간선을 저장한다.
- 정점의 수:N, 간선의 수:E인 무방향 그래프의 경우
- N개의 리스트, N개의 배열, 2E개의 노드가 필요
- 방향 그래프 : E개의 리스트 노드
- 트리에서는 특정 노드 하나(루트노드) 에서 다른 모든 노드로 접근이 가능 -> TREE 클래스 불필요
- 그래프에선 특정 노드에서 다른 모든 노드로 접근이 가능하지 않음 -> GRAPH 클래스 불필요
- c++ 선언문 : n개의 linked list로 선언
Chain<int> *adjList;
LinkedGraph(const int vertices=0); n(vertices), e(0)
{adjList=new Chain<int>[n];}
인접 리스트와 인접 행렬 중 선택 방법
- 인접 리스트
- 그래프 내에 적은 숫자의 간선만을 가지는 희소 그래프(Sparse Graph)의 경우
- 장점
- 어떤 노드에 인접한 노드들을 쉽게 찾을 수 있다.
- 그래프에 존재하는 모든 간선의 수는 O(N+E)안에 알 수 있다. : 인접 리스트 전체를 조사한다.
- 단점
- 간선의 존재 여부와 정점의 차수 : 정점 i의 리스트에 있는 노드의 수, 즉 정점 차수 만큼의 시간이 필요
- 인접 행렬
- 그래프에 간선이 많이 존재하는 밀집 그래프의 경우(Dense Graph)
- 장점
- 두 정점을 연결하는 간선의 존재 여부(M[i][j])를 O(1)안에 즉시 알 수 있다.
- 정점의 차수는 O(n) 안에 알 수 있다. : 인접 배열의 i번째 행 또는 열을 모두 더한다
- 단점
- 어떤 노드에 인접한 노드들을 찾기 위해서는 모든 노드를 전부 순회해야 한다.
- 그래프에 존재하는 모든 간선 수는 O(N^2) 안에 알 수 있다. : 인접 행렬 전체를 조사한다.
그래프의 탐색
깊이 우선 탐색 (DFS, Depth-First Search)
루트 노드(혹은 다른 임의의 노드)에서 시작해서 다음 분기(branch)로 넘어가기 전에 해당 분기를 완벽하게 탐색하는 방법.
- 즉 넓게(wide) 탐색하기 전에 깊게(deep) 탐색하는 것이다.
- 사용하는 경우 : 모든 노드를 방문 하고자 하는 경우에 이 방법을 선택한다.
- 깊이 우선 탐색이 너비 우선 탐색보다 좀 더 간단하다.
너비 우선 탐색 (BFS, Breadth-First Search)
루트 노드(혹은 다른 임의 노드)에서 시작해서 인접한 노드를 먼저 탐색하는 방법
- 즉 깊게(deep) 탐색하기 전에 넓게(wide) 탐색하는 것이다.
- 사용하는 경우 : 두 노드 사이의 최단 경로 혹은 임의이 경로를 찾고 싶을 때 이 방법을 선택한다.
- ex) 지구상에 존재하는 모든 친구 관계를 그래프로 표현한 후 ash와 vanessa 사이에 존재하는 경로를 찾는 경우
- 깊이 우선 탐색의 경우 : 모든 친구 관계를 다 살펴봐야 할 지도 모른다.
- 너비 우선 탐색의 경우 : ash와 가까운 관계부터 탐색