๐ง 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๊ฐ ๋ญ๋๊ตฌ์?
๋ค์ ๊ธ์์ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
'๐ฅ Computer Science > ์๊ณ ๋ฆฌ์ฆ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๐ง 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๊ฐ ๋ญ๋๊ตฌ์?
๋ค์ ๊ธ์์ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.