深度优先遍历和广度优先遍历
深度优先遍历 递归版本
const dfs1 = (node, nodeList = []) => {
if (node !== null) {
nodeList.push(node)
const children = node.children || []
for (let i = 0; i < children.length; i++) {
dfs1(children[i], nodeList) // 展开子节点
}
}
return nodeList
}
深度优先遍历 非递归实现
const dfs2 = (node) => {
let nodes = []
let stack = [] // 栈:先进后出
if (node) {
stack.push(node) // 第一个元素进来
while (stack.length) {
let item = stack.pop() // 弹出最后一个元素
let children = item.children // 获取子元素
nodes.push(item) // 将元素放进结果集
for (let i = children.length - 1; i >= 0; i--) {
// for循环是从反向遍历,最后一个元素先进入栈内,第一个元素在栈的最外层
// while循环再次循环时,pop会取到第一个元素,因为第一个元素是最后入栈的
// 然后再开展子元素,子元素被遍历时会添加到栈内。
// 第一个元素被取出来之后进入的元素是第一个元素的子元素,while再次循环时取到的就是第一个子元素的children
// 使用栈的特性完成深度优先遍历
stack.push(children[i])
}
}
}
return nodes
}
广度优先遍历
const bfs = (node) => {
let nodes = []
let queue = [] // 广度优先遍历使用队列的特性
if (node) {
queue.push(node)
while(queue.length) {
let item = queue.shift() // 取数组第一项
let children = item.children || []
nodes.push(item) // 元素放入结果集
for (let i = 0; i < children.length; i++) {
/**
* for 循环正向循环,将元素放入队列中,第一个元素就是当前元素的第一个children
* while循环时会从队首取值然后将队首的子元素加到队列到末尾
* 靠近队首的是最先被添加进去的,每次消费都是将前面的一级子元素添加到队列里
* 以此实现广度优先遍历
*/
queue.push(children[i])
}
}
}
return nodes
}