๐ง DFS (Depth-First Search) - ๊น์ด์ฐ์ ํ์
์ด์ ๊ธ์์ ์ดํด๋ณธ explore procedure๋ฅผ ์ด์ฉํ์ฌ ๊ทธ๋ํ ์์ ๋ชจ๋ ์ ์ ์ ํ๋ฒ์ฉ ๋ฐฉ๋ฌธํ๋ ๋ฐฉ๋ฒ์ธ DFS ์๊ณ ๋ฆฌ์ฆ์ ๋ํด ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๋ค ์์๋ดค์ต๋๋ค :)
์ฝ๋๋ก ๊ตฌํ
๋ค์ ๊ทธ๋ํ์ ๋ํ dfs๋ฅผ ์ฝ๋๋ก ๊ตฌํํด ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
/**
* Created by ShinD on 2022/09/22.
*/
fun main() {
val graph = GraphMaker().make()
GraphExplorer().dfs(graph)
GraphMaker.vertexSet().forEach {
println("END [${it.value}], [ ${it.preOrder}, ${it.postOrder} ]")
}
}
class Graph(
val vertexSet: Set<Vertex>,
val graph: List<List<Vertex>>,
)
class GraphMaker {
companion object {
val a = Vertex('a')
val b = Vertex('b')
val c = Vertex('c')
val d = Vertex('d')
val e = Vertex('e')
val f = Vertex('f')
val g = Vertex('g')
val h = Vertex('h')
val i = Vertex('i')
val j = Vertex('j')
val k = Vertex('k')
val l = Vertex('l')
fun vertexSet(): Set<Vertex> {
return setOf(
a, b, c, d, e, f, g, h, i, j, k, l
)
}
}
fun make(): Graph {
return Graph(
vertexSet = vertexSet(),
graph = listOf(
listOf(b, e), // a
listOf(a), // b
listOf(d, g, h), // c
listOf(c, h), // d
listOf(a, i, j), // e
listOf(), // f
listOf(c, h, k), // g
listOf(c, d, g, k ,l), // h
listOf(e, j), // i
listOf(e, i), // j
listOf(g, h), // k
listOf(h), // l
)
)
}
}
class Vertex(
val value: Char,
var preOrder: Int = 0,
var postOrder: Int = 0,
var isVisited: Boolean = false,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Vertex) return false
if (preOrder != other.preOrder) return false
if (postOrder != other.postOrder) return false
if (value != other.value) return false
return true
}
override fun hashCode(): Int {
var result = preOrder
result = 31 * result + postOrder
result = 31 * result + value.hashCode()
return result
}
}
class GraphExplorer {
// ์์ ์ 1๋ก ์ด๊ธฐํ
private var counter = 1
private fun visited(vertex: Vertex) {
vertex.isVisited = true
println("VISIT [${vertex.value}]")
}
private fun preVisit(vertex: Vertex) {
vertex.preOrder = counter
counter++
}
private fun postVisit(vertex: Vertex) {
vertex.postOrder = counter
counter++
}
fun explore(
graph: Graph,
root: Vertex,
) {
val idx = root.value - 'a'
// ๋ฐฉ๋ฌธ ์ฒ๋ฆฌ
visited(root);
// preVisit
preVisit(root);
// ๋ฃจํธ vertex์ adjacent ํ ๋ชจ๋ vertex ํ์
graph.graph[idx].forEach { vertex ->
/// ์์ง ๋ฐฉ๋ฌธํ์ง ์์๋ค๋ฉด explore
if (!vertex.isVisited) explore(graph, vertex)
}
// postVisit
postVisit(root);
}
fun dfs(
graph: Graph,
) {
// ๋ชจ๋ Vertex์ ๋ํด์ visited๋ฅผ false๋ก ์ด๊ธฐํ
graph.vertexSet.forEach { it.isVisited = false }
// ๋ชจ๋ Vertex๋ฅผ ๋ฐฉ๋ฌธํ ๋๊น์ง ๋ฐ๋ณตํ๋ค.
graph.vertexSet.forEach {
// ๋ฐฉ๋ฌธํ์ง ์์ Vertex ํ๋์์ explore ์คํ
if (!it.isVisited) explore(graph, it)
}
}
}
๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์กฐ๊ธ ์์์ ์์๋ณด์๋ฏ์ด explore procedure ๊ณผ์ ์ DFS tree๋ก ๋ํ๋ผ ์ ์์ต๋๋ค.
๋ฐ๋ผ์ explore ๊ณผ์ ์ ๋ฐ๋ณตํ๋ DFS ์๊ณ ๋ฆฌ์ฆ์ ๊ฒฝ์ฐ์๋
์ ์ฒด ๊ณผ์ ์ DFS tree๋ค์ ์๋ก์ ํฉ์งํฉ(disjoint union), ์ฆ forest๋ก ํํ ๊ฐ๋ฅํฉ๋๋ค.
์ด๋ DFS forest๋ฅผ ์ด๋ฃจ๋ ๊ฐ๊ฐ์ DFS tree๋ ๊ทธ๋ํ ์์์ Connected Component์ ๋์ํฉ๋๋ค.
Connected Component๊ฐ ๋ญ๋๊ตฌ์?
๋ค์ ๊ธ์์ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.