邻接表的形式表示一个图:
const graph = {
0: [1,2],
1: [2],
2: [3,0],
3: [3,0]
}
深度优先遍历
深度优先遍历就是优先遍历完一条完整路径,和树的深度优先遍历基本一样,但是需要用visited
来记录遍历过的节点,以避免死循环。
// 记录访问过的节点
const visited = new Set()
const dfs = cur => {
console.log(cur)
visited .add(cur)
graph[n].forEach( node => {
if(!visited.has(node)){
// 如果没有访问过当前节点
dfs(node)
}
})
}
广度优先遍历
广度优先遍历就是优先遍历完一个节点的所有子节点,也是需要一个visited
来记录遍历过的节点。
下面踩一个坑:
const visited = new Set()
const bfs = n => {
const queue = [n]
while(queue.length > 0) {
const cur = queue.shift()
// 在这里写是错误的
visited.add(n)
console.log(cur)
graph[cur].forEach( node => {
if(!visited.has(node)){
queue.push(node)
}
})
}
}
上面的思路是,每次出队的时候,再把这个出队元素加入到visited
里,这样做是有问题的:
当我们从2出发遍历整个图的时候,队列初始值为[2]
,visited
的初始值为空。
按照队列的顺序让2出队并加入到visited
数组,此时队列是[]
,visited
是[2]
。2的相邻节点是3和0,因为0,3都不在visited里,入队,此时的队列是[3,0]
;
按照队列的顺序让3出队并加入到visited
数组,此时队列是[0]
,visited
是[2,3]
。3的相邻节点是3和0,因为0不在visited里,入队,此时的队列是[0,0]
;
问题来了,队列里出现了重复的节点,意味着这个节点会被遍历不止一次,bug就在这里。
要解决这个bug,只要把节点加入visited
的语句放在入栈之后,而不是出栈之后,就OK了。
const visited = new Set()
const bfs = n => {
const queue = [n]
visited.add(n)
while(queue.length > 0) {
const cur = queue.shift()
// 在这里写是错误的
console.log(cur)
graph[cur].forEach( node => {
if(!visited.has(node)){
queue.push(node)
visited.add(node)
}
})
}
}