JavaScript 递归之深度优先和广度优先

JavaScript 递归之深度优先和广度优先

在前端工作当中,经常会遇到树组件、树形表格、机构树等功能,这个时候就需要对后端返回的数据进行处理,在对树形数据处理时,一般是需要用到递归来处理,而递归又分为了深度优先和广度优先,这里给出了两种递归方法的示例。

在这里插入图片描述

1 数据准备

这里是示例当中用到的数据

const tree = {
  id: 1,
  children: [
    {
      id: 2,
      children: [
        {
          id: 4,
          children: [
            { id: 8 },
            { id: 9 },
          ]
        },
        { id: 5 },
      ]
    },
    {
      id: 3,
      children: [
        { id: 6 },
        { id: 7 },
      ]
    },
  ]
};

2 深度优先

顾名思义,深度优先的意思就是以深度为主。我们可以把树机构的分支看作为一个个路径,当进行深度优先的递归时,程序会在一条路径下,一直走下去,直到不能在走为止,然后换一个路径继续走到底,走的层级很深。

通过代码打印的 1, 2, 4, 8, 9 可以看到是把第一个分支里面走到了底。

代码示例:

function recursion(list){
  list.forEach(item => {
    console.log(item.id); // 打印id
    if(item.children){
      recursion(item.children);
    }
  });
}
recursion([tree]); // 调用函数,会依次打印:1, 2, 4, 8, 9, 5, 3, 6, 7

3 广度优先

前面说深度优先是一条道走到底,类似于遇见了岔道,一条岔道走到了底,直到无路可走,而广度优先则恰恰相反,广度优先是把每一个层级的所有选择都走一遍,只有当第一个层级走完之后,才会走第二个层级。

以上面的图为例,先走到1,然后1走完之后,遇见了2和3,广度优先时会先走一下2和3,走完之后,再处理4和5,顺序为1 > 2 > 3 > 4 > 5 > 6 > 7 > 8 > 9

代码示例:

// 方法一:
// 先遍历当前节点,forEach当中找到当前项所有的子节点,放到同一个数组当中
// 也就是找到下一层级的全部节点
let tempArr = [];
function recursion(list){
  tempArr = [];
  list.forEach(item => {
    console.log(item.id);
    if(item.children){
      tempArr = tempArr.concat(item.children);
    }
  });
  tempArr.length > 0 && recursion(tempArr);
}
recursion([tree]); // 调用函数,会依次打印:1, 2, 3, 4, 5, 6, 7, 8, 9

// 方法二:使用队列的思想,先进先出,依次将节点加入到数组当中,再从前面弹出
function queueRecursion(){
  while (tempArr.length){
    let item = tempArr.shift(); // 弹出第一个
    console.log(item.id);
    if(item.children){
      tempArr = tempArr.concat(item.children); // 添加节点
    }
  }
}
let tempArr = [];
tempArr = [tree]; 
queueRecursion(); // 调用函数,会依次打印:1, 2, 3, 4, 5, 6, 7, 8, 9
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是JavaScript树的深度优先遍历和广度优先遍历算法的实现: ```javascript // 定义树节点 class TreeNode { constructor(val) { this.val = val; this.left = null; this.right = null; } } // 深度优先遍历(递归) function dfs(root) { if (!root) return; console.log(root.val); dfs(root.left); dfs(root.right); } // 深度优先遍历(非递归) function dfs2(root) { if (!root) return; const stack = [root]; while (stack.length) { const node = stack.pop(); console.log(node.val); if (node.right) stack.push(node.right); if (node.left) stack.push(node.left); } } // 广度优先遍历 function bfs(root) { if (!root) return; const queue = [root]; while (queue.length) { const node = queue.shift(); console.log(node.val); if (node.left) queue.push(node.left); if (node.right) queue.push(node.right); } } // 创建一棵树 const root = new TreeNode(1); root.left = new TreeNode(2); root.right = new TreeNode(3); root.left.left = new TreeNode(4); root.left.right = new TreeNode(5); root.right.left = new TreeNode(6); root.right.right = new TreeNode(7); // 深度优先遍历 dfs(root); // 输出:1 2 4 5 3 6 7 // 深度优先遍历(非递归) dfs2(root); // 输出:1 3 7 6 2 5 4 // 广度优先遍历 bfs(root); // 输出:1 2 3 4 5 6 7 ``` 以下是以邻接表为存储结构,实现连通无向图的深度优先广度优先遍历的实现: ```python # 定义图节点 class GraphNode: def __init__(self, val): self.val = val self.neighbors = [] # 深度优先遍历 def dfs(node): if not node: return visited = set() stack = [node] while stack: cur = stack.pop() if cur not in visited: visited.add(cur) print(cur.val) for neighbor in cur.neighbors: stack.append(neighbor) # 广度优先遍历 def bfs(node): if not node: return visited = set() queue = [node] while queue: cur = queue.pop(0) if cur not in visited: visited.add(cur) print(cur.val) for neighbor in cur.neighbors: queue.append(neighbor) # 创建一个图 node1 = GraphNode(1) node2 = GraphNode(2) node3 = GraphNode(3) node4 = GraphNode(4) node5 = GraphNode(5) node6 = GraphNode(6) node1.neighbors = [node2, node3] node2.neighbors = [node1, node4, node5] node3.neighbors = [node1, node6] node4.neighbors = [node2] node5.neighbors = [node2, node6] node6.neighbors = [node3, node5] # 深度优先遍历 dfs(node1) # 输出:1 3 6 5 2 4 # 广度优先遍历 bfs(node1) # 输出:1 2 3 4 5 6 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值