深度优先遍历和广度优先遍历属于图算法。
这里简单介绍这两种方法并使用JS实现。

一. 定义

深度优先遍历:指从某个顶点出发,首先访问这顶点,然后找出刚访问的这个结点的第一个未被访问的邻节点,然后从这个邻结点为顶点,继续找出它的下一个顶点进行访问。重复此步骤,直到所有节点被访问完为止。
广度优先遍历:从某个顶点出发,首先访问这个顶点,然后找出刚访问的这个结点的所有未被访问的邻结点,访问完后再访问这些结点中第一个邻结点的所有结点。重复此方法,直到所有节点被访问完为止。

简单来说,深度优先是自上而下的遍历搜索,广度优先是逐层遍历

二. 区别

对于算法,无非是时间复杂度与空间复杂度之间的较量

  • 深度优先不需要记住所有的节点,所以占用空间小;而广度优先需要记住所有的节点,占用空间大;
  • 深度优先有回溯的操作(没有路走了需要回头),所以相对而言时间会更长些。

深度优先采用的是堆栈的形式,即先进后出
广度优先则采用队列的形式,即先进先出

三. 实现(使用JS)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// 需要遍历的数据
const data = [
{
name: 'a',
children: [
{ name: 'b', children: [{ name: 'e' }] },
{ name: 'c', children: [{ name: 'f' }] },
{ name: 'd', children: [{ name: 'g' }] },
]
},
{
name: 'A',
children: [
{ name: 'B', children: [{ name: 'E' }] },
{ name: 'C', children: [{ name: 'F' }] },
{ name: 'D', children: [{ name: 'G' }] },
]
}
]

// 使用递归的深度优先遍历
function deepTraversal(data) {
const result = []
data.forEach(item => {
const map = data => {
result.push(data.name)
data.children
&& data.children
.forEach(child => map(child))
}

map(item)
})
return result.join(', ')
}

// 广度遍历
function wideTraversal(data) {
let result = []
let queue = data
while (queue.length > 0) {
[...queue].forEach(child => {
queue.shift()
result.push(child.name)
child.children
&& queue.push(...child.children)
})
}
return result.join(', ')
}

deepTraversal(data) // a, b, e, c, f, d, g, A, B, E, C, F, D, G
wideTraversal(data) // a, A, b, c, d, B, C, D, e, f, g, E, F, G