cf. 이전에 배운 트리를 rooted tree 라고 부른다.
spanning subgraph 가 트리인 그래프.
연결 그래프의 spanning subgraph 가 tree 조건을 만족하면 Spanning Tree 라고한다.
즉, 사이클이 없으며 연결 그래프이고 기존 그래프 G의 모든 정점을 포함하는 그래프이다.
다시말해, 원래 그래프 G가 트리가 아니라면 spanning tree 는 유일하지 않을 수 있다.
Algorithm DFS(G)
Input graph G
Output labeling of the edges of G
as discovery edges and back edges
for all u ∈ G.vertices() // 모든 정점과 간선의 label를 UNEXPLORED로 초기화 => 각각 엣지시퀀스와 정점시퀀스 따라가면서 모든 엣지 및 정점 오브젝트의 label 필드를 0으로 초기화하는 작업 : O(n) / O(m)
u.setLabel(UNEXPLORED)
for all e ∈ G.edges()
e.setLabel(UNEXPLORED)
for all v ∈ G.vertices() // 모든 정점에 대해 탐색
if v.getLabel() = UNEXPLORED // 아직 방문안한 정점이면
DFS(G, v) // DFS 탐색실행
Algorithm DFS(G, v) // 현재 보고있는정점 : v
Input graph G and a start verrtex v of G
Output labeling of the edges of G
in the connected component of v
as discovery edges and back edges
v.setLabel(VISITED) // 현재 정점을 방문처리 : O(1)
for all e ∈ G.incidentEdges(v) // 현재 정점과 인접한 모든 간선중에 아직 확인 안해본 간선들에 대해 탐색
if e.getLabel() = UNEXPLORED // 한번도 아직 확인안해본 간선이라면 => 색깔 확인하는데 O(1)
w = e.opposite(v)
if w.getLabel() = UNEXPLORED // 해당 간선이 가리키고 있는 반대편 정점을 확인해보니, 이 정점이 아직 방문 안한 곳이라면
e.setLabel(DISCOVERY) // 정점을 향해 가본 간선임을 표시. 단, 왔던 길을 다시 돌아가면 안된다는 뜻도 포함되어있다!
DFS(G, w) // 함수 호출하는데 O(1)
else // 이 정점이 아까 방문 했던 곳이라면
e.setLabel(BACK) // 간선이 아까 방문했던 정점을 향해가는 간선이라고 표시 => O(1)
(다른 작업은 모두 O(1)이기 때문)
=> 인접리스트로 구현했다면 O(deg(v) + 1) 이다.
1) O(deg(v))
2) O(1)
여러개의 vertex 로 뻗어나가서 탐색을 진행할 수 있을떄, 알파벳 순으로 탐색을 진행한다고 가정하자.
DFS(G) 로 모든 정점과 간선을 UNEXPLORED 를 초기화한다.
이후 DFS(G, A) 를 호출
A와 인접한 간선들을 조사한다 (간선 AB, AB, AD, AE 순으로)
간선 AB가 UNEXPLORED이므로 B 가 UNEXPLORED 인지 조사한다.
B가 UNEXPLORED 이므로 간선 AB 를 EXPLORED 로 바꾸고 DFS(G, B) 를 호출한다.
B를 VISITED 표시한다.
B와 인접한 간선을 조사한다. ( 간선 BA, BC 순으로 )
간선 BA가 UNEXPLORED가 아니므로 BACK 표시하고 간선 BC 를 조사한다.
간선 BC 가 UNEXPLORED 이고 C 도 UNEXPLORED 이므로 DFS(G, B) 를 실행한다.
이런식으로 계속 진행됨!
cf. ABCDE 와 연결되지 않은 connectes component 인 FG가 있을때 한번 DFS(F)로 옮겨온다음 여기도 마찬가지로 방문함!
DFS(G, v) 는 v 와 연결된 conntected component 를 방문한다
DFS(G, v) 의 결과에서 DISCOVERY 간선으로 연결된 그래프는
v와 연결된 conntected component 의 spanning tree 이다.
(cf. 모든 정점을 연결하면서 순회하지 않는 최대의 단위라는 뜻)
DFS를 인접리스트로 구현했을때 수행시간이 O(n+m) 이 걸리는 이유는 아래와 같다.
모든 정점, 간선 label 초기화 => O(n+m)
Σv ( O(1) + O(deg(v)) ) = 2m = O(m)
실제 수행에도 모든 정점에 대해 O(1)+O(deg(v)) 시간이 걸림
2-1. 현재 탐색하는 정점의 incidence 시퀀스의 모든 엣지 오브젝트에 대해 방문처리(label 필드값 변경) => deg(v)
2-2. 해당 정점도 처리해야 하므로 => O(1)
=> 이 작업을, 즉 O(1) + O(deg(v)) 작업을 모든 정점에 대해서 수행한다.
따라서 O(n+m) + O(m) = O(n+m) 이다!