JS 深度优先遍历与广度优先遍历 实现查找

在日常的开发工作中,牵扯到层级结构比较复杂的节点,如树形节点,级联选择器,这些都是牵扯到前端算法的遍历的;本文将介绍常用到的两种遍历方式:深度优先遍历和广度优先遍历

深度优先遍历:depth first search
广度优先遍历:breadth first search

目录

1.示意图

2.具体的代码示例

2.1.深度优先遍历

2.2.广度优先遍历

3.总结


1.示意图

通过两组示意图来明白什么叫做深度优先遍历和广度优先遍历

  • 图一(深度遍历示意图)

深度遍历查找会按照图中绿色标注的数字去查找,就相当于是一条道走到黑,如果没有叶子节点的话,会再拐回来,回溯到上一个节点再搜索其余的,按照同样一条道走到黑的过程去遍历,直到把整个节点都遍历完了就停止遍历;

  • 图二(广度遍历示意图)

广度遍历的遍历顺序如图所示,也是按照我上图标注的数字大小去先后遍历的,不要太在意颜色的不同,我之所以把颜色用不同的来标注是因为我想要强调的是:广度遍历是先把同级的节点遍历完毕以后再去遍历下级节点,直到把所有节点都遍历完毕以后就停止遍历;相当于警察抓小偷的游戏中,警察们从一个点由里圈向外圈一圈一圈发散那样去抓一个小偷一样。

2.具体的代码示例

以树形节点为例子,用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":[]
        }
      ]
    }
  ]

2.1.深度优先遍历

深度优先查找(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]

2.2.广度优先遍历

广度优先查找(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]

3.总结

以上的两种方法就是本篇的重点内容了,如果对你的开发有帮助的话,欢迎点赞或评论

主要是参考了这篇文章:https://juejin.cn/post/6844903893118238733#heading-2

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值