通过递归算法对执行栈的理解

通过递归算法对执行栈的理解

在工作中经常遇到树形结构的场景,数据的类型大致分为两类 1. [{children: [...]}]这种list children的形式, 2. [{id: 1}, {parentId: 1}]构成的{id: 1, children: { parentId: 1 }}这种形式,

如果是数据1 的这种结构,就使用递归遍历数据即可,对于数据2 则需要先将打平的数据转化为 数据1 的格式。

将下面结构转为树形结构

[
  {
    id: 1,
    pid: '',
    name: '北京市'
  },
  {
    id: 2,
    pid: 1,
    name: '海淀区'
  },
  {
    id: '2-2',
    pid: 2,
    name: '知春路'
  },
  {
    id: '2-3',
    pid: 2,
    name: '中关村'
  },
  {
    id: '2-1',
    pid: 2,
    name: '西二旗'
  },
  {
    id: 3,
    pid: 1,
    name: '昌平区'
  },
  {
    id: '3-1',
    pid: 3,
    name: '回龙观'
  },
  {
    id: '3-2',
    pid: 3,
    name: '朱辛庄'
  },
  {
    id: 4,
    pid: 1,
    name: '朝阳区'
  },
  {
    id: '4-2',
    pid: 4,
    name: '三元桥'
  },
]
function arrToTree(list, rootValue) {
  let treeData = [] // 新建数组 , 用来储存当前对象的子对象
  list.forEach(item => {
      // 遍历寻找子对象
      if (item.pid === rootValue) {
          // 递归  返回对象的children列表
          const children = arrToTree(list, item.id)
          // 如果有children就将数组添加给对象
          if (children.length) {
              item.children = children
          }
          // 将完整的item添加给导出的数组
          treeData.push(item)
      }
  })
  return treeData // 每次递归会返回当前的子列表
}

const treeData = arrToTree(list, '')

上面执行 过程中,首先创建全局的执行栈 arrToTree 执行的时候, push 到执行栈中,在它的作用域内遍历list, 判断 list中元素的pid 是不是等于传入的rootValue 如果等于, 就递归执行 arrToTree, 将新的 rootValue 传入,生成一个新的函数作用域,push 到执行栈中, 依次递归执行,一直到 不满足 item.pid === rootValue ,函数执行完 返回 treeData 然后 pop 出执行栈。

如果还是不清楚,可以按照下面的思路 自己理解下
1. 创建全局执行栈
2. arrToTree 函数push 到执行栈 函数接收的参数是 list, '' .下面元素

{
    id: 1,
    pid: '',
    name: '北京市'
  },

满足条件,所以递归执行了arrToTree 参数为 list, 1
3. arrToTree 函数push 到执行栈 此时执行栈是这样的

[全局上下文,第二部函数执行上下文, 第三步函数执行上下文]

此时还是遍历list
下面元素

{
    id: 2,
    pid: 1,
    name: '海淀区'
  },

满足条件, 所以递归执行了arrToTree 参数为 list, 2
4. arrToTree 函数push 到执行栈
此时执行栈是这样的

[全局上下文,第二部函数执行上下文, 第三步函数执行上下文,第四步函数上下文]

此时还是遍历list
下面元素

{
    id: '2-2',
    pid: 2,
    name: '知春路'
  },

满足条件,所以递归执行了arrToTree 参数为 list, 2-2
5. arrToTree 函数push 到执行栈
此时执行栈是这样的

[全局上下文,第二部函数执行上下文, 第三步函数执行上下文,第四步函数上下文,第五步函数上下文]

此时还是遍历list , 这个时候 没有元素满足条件 所以函数返回了[]. 并且将该上下文 pop 出执行栈 也就回到了第四步执行上下文, 第四步中的 treeData 应为第五步返回的是空数组就push 了

{
    id: '2-2',
    pid: 2,
    name: '知春路'
  },

在第四步的上下文中继续遍历 第二个符合条件的是

{
    id: '2-3',
    pid: 2,
    name: '中关村'
  },

递归执行了arrToTree 参数为 list, 2-3
在执行栈中添加新的上下文,继续执行,发下没有满足条件的,返回了空数组, 再pop 出执行栈,然后应为返回的是空数组, 所以将元素中关村的内容 也push 到 第四步的执行上下文 treeData,

接着遍历 发现 西二旗 的内容也满足, 重复上面的步骤,最后 返回第四步的上下文后,此时 treeData 中有 知春路,中关村,西二旗三组数据,第四步上下文没有满足条件的情况下 返回 treeData ,将第四步上下文 pop 出执行栈, 来到第三步执行栈, 应为返回的treeData.length > 0 给该执行栈 当前元素 海淀区 创建一个key ="children" ,value= treeData

第三步执行栈中接着遍历, 发现下一个满足条件的元素 name 为 昌平区 ,重复上面第四步的步骤
。。。
第三步执行栈中接着遍历, 发现下一个满足条件的元素 name 为 朝阳区 ,重复上面第四步的步骤

第三步上下文执行完后,pop 出执行栈,返回 trueData

没有满足第三步条件的情况下, 将 第三步上下文 pop 出执行栈

接着执行 第二部执行栈 最后执行完后 再pop 出执行栈,

到全局执行栈的时候, 也就返回了最终的结果

下面是我的小程序体验码,希望能和大家共同学习进步

posted @ 2022-12-01 10:15  eyes-star  阅读(18)  评论(0编辑  收藏  举报