在日常的开发工作中,牵扯到层级结构比较复杂的节点,如树形节点,级联选择器,这些都是牵扯到前端算法的遍历的;本文将介绍常用到的两种遍历方式:深度优先遍历和广度优先遍历
深度优先遍历:depth first search
广度优先遍历:breadth first search
目录
1.示意图
2.具体的代码示例
2.1.深度优先遍历
2.2.广度优先遍历
3.总结
通过两组示意图来明白什么叫做深度优先遍历和广度优先遍历
深度遍历查找会按照图中绿色标注的数字去查找,就相当于是一条道走到黑,如果没有叶子节点的话,会再拐回来,回溯到上一个节点再搜索其余的,按照同样一条道走到黑的过程去遍历,直到把整个节点都遍历完了就停止遍历;
广度遍历的遍历顺序如图所示,也是按照我上图标注的数字大小去先后遍历的,不要太在意颜色的不同,我之所以把颜色用不同的来标注是因为我想要强调的是:广度遍历是先把同级的节点遍历完毕以后再去遍历下级节点,直到把所有节点都遍历完毕以后就停止遍历;相当于警察抓小偷的游戏中,警察们从一个点由里圈向外圈一圈一圈发散那样去抓一个小偷一样。
以树形节点为例子,用JS代码实现两种查找方式:
// 这个是要进行遍历的树形节点
const root = [
{
"id":1,
"pid":null,
"key":1,
"title":"1-1111",
"children":[
{
"id":2,
"pid":1,
"key":2,
"title":"2-1111",
"children":[
{
"id":4,
"pid":2,
"key":4,
"title":"8-1111",
"children":[]
},
{
"id":5,
"pid":2,
"key":5,
"title":"9-1111",
"children":[
{
"id":7,
"pid":5,
"key":7,
"title":"5-1111",
"children":[]
},
{
"id":8,
"pid":5,
"key":8,
"title":"8-1111",
"children":[]
},
]
},
{
"id":6,
"pid":2,
"key":6,
"title":"10-1111",
"children":[]
},
]
},
{
"id":3,
"pid":1,
"key":3,
"title":"9-1111",
"children":[]
}
]
}
]
深度优先查找(depth first search),采用栈结构,后进先出,JS用递归实现和没有用递归实现
// 用递归实现深度优先遍历
const depthFirstSearchWithRecursive = source => {
const result = []; // 存放结果的数组
// 递归方法
const dfs = data => {
// 遍历数组
data.forEach(element => {
// 将当前节点 id 存放进结果
result.push(element.id);
// 如果当前节点有子节点,则递归调用
if (element.children && element.children.length > 0) {
dfs(element.children);
}
});
};
// 开始搜索
dfs(source);
return result;
};
const s = depthFirstSearchWithRecursive(root)
console.log(s);// 结果为 [1, 2, 4, 5, 7, 8, 6, 3]
// 不用递归实现深度遍历优先
const depthFirstSearchWithoutRecursive = source => {
const result = []; // 存放结果的数组
// 当前栈内为全部数组
const stack = JSON.parse(JSON.stringify(source));
// 循环条件,栈不为空
while (stack.length !== 0) {
// 最上层节点出栈
const node = stack.shift();
// 存放节点
result.push(node.id);
// 如果该节点有子节点,将子节点存入栈中,继续下一次循环
const len = node.children && node.children.length;
for (let i = len - 1; i >= 0; i -= 1) {
stack.unshift(node.children[i]);
}
}
return result;
};
const s = depthFirstSearchWithoutRecursive(root)
console.log(s);// 结果为 [1, 2, 4, 5, 7, 8, 6, 3]
广度优先查找(breadth first search),采用栈结构,后进先出,JS用递归实现和没有用递归实现
const breadthFirstSearch = source => {
const result = []; // 存放结果的数组
// 当前队列为全部数据
const queue = JSON.parse(JSON.stringify(source));
// 循环条件,队列不为空
while (queue.length > 0) {
// 第一个节点出队列
const node = queue.shift();
// 存放结果数组
result.push(node.id);
// 当前节点有子节点则将子节点存入队列,继续下一次的循环
const len = node.children && node.children.length;
for (let i = 0; i < len; i += 1) {
queue.push(node.children[i]);
}
}
return result;
};
const s = breadthFirstSearch(root)
console.log(s);// 结果为 [1, 2, 3, 4, 5, 6, 7, 8]
以上的两种方法就是本篇的重点内容了,如果对你的开发有帮助的话,欢迎点赞或评论
主要是参考了这篇文章:https://juejin.cn/post/6844903893118238733#heading-2