题目:
将一维数组,转化成嵌套的tree
利用一个中间对象把数组之间node的关系体现到对象里,然后利用引用类型逻辑来构造tree

const arr = [
    { id: 1, title: "child1", parentId: 0 },
    { id: 2, title: "child2", parentId: 0 },
    { id: 3, title: "child1_1", parentId: 1 },
    { id: 4, title: "child1_2", parentId: 1 },
    { id: 5, title: "child2_1", parentId: 2 }
  ]

const buildChildrenArr = (arr) => {
    const res = [];
    const map = {};
    for ( let i = 0; i < arr.length; i++) {
      map[arr[i].id] = { ...arr[i], children: []};
      const key = arr[i].id;
      if (!map[key].parentId) {
        res.push(map[key]) // 只有根node会进去
      } else {
        const parentId = map[key].parentId
        if (parentId === map[parentId].id) {
          map[parentId].children.push(map[key]) // 注意这里打入的不能是arr[i]
        }
      }
    }
    return res;
  };

  console.log('buildChildrenArr', buildChildrenArr(arr));

也可以用递归的方式写,等我研究清楚了再补充(其实一直都觉得,递归不太好理解,尴尬)

function buildTree(arr, parentId) {
    const result = [];
    for (let i = 0; i < arr.length; i++) {
      const item = arr[i];
      if (item.parentId === parentId) {
        const children = buildTree(arr, item.id);
        if (children.length > 0) {
          item.children = children;
        }
        result.push(item);
      }
    }
    return result;
  }
  
  
  const tree = buildTree(arr, 0);

有时候不太理解递归,其实递归就是剥洋葱

是的,递归函数的执行过程可以比喻为剥洋葱的过程。在递归函数调用时,每一次递归都会将当前函数的参数和局部变量压入栈中,然后进入下一层递归函数的调用。当递归到最深层时,开始从内层开始一层一层地出栈,直到回到最初的调用处,整个递归过程才算结束。

举个例子,假设有一个递归函数factorial计算阶乘,代码如下:

function factorial(n) {
  if (n === 0) {
    return 1;
  }
  return n * factorial(n - 1);
}

当调用factorial(4)时,递归调用的过程可以用如下图示表示:

factorial(4)
  -> factorial(3)
    -> factorial(2)
      -> factorial(1)
        -> factorial(0)
        <- 1
      <- 1
    <- 2
  <- 6

在调用factorial(4)时,首先进入第一层递归,将n的值压入栈中。然后进入第二层递归,将n-1的值压入栈中。随着递归的不断深入,每一层递归都会将自己的参数和局部变量压入栈中,直到递归到最深层,即factorial(0)时,开始从内层开始一层一层地出栈。最后,当栈中所有函数都完成执行并返回结果时,整个递归过程才算结束。

每次写递归,都按照这三要素来写,可以保证大家写出正确的递归算法!

确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程

比如以下是一个快排:

function quickSort(arr) {
    if (arr.length <= 1) {
      return arr;
    }
    const pivotIndex = Math.floor(arr.length / 2);
    const pivot = arr.splice(pivotIndex, 1)[0];
    const left = [];
    const right = [];
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] < pivot) {
        left.push(arr[i]);
      } else {
        right.push(arr[i]);
      }
    };
    return quickSort(left).concat([pivot], quickSort(right));
  }

const arr = [3, 1, 4, 5, 0];
const sortedArr = quickSort(arr);
console.log(sortedArr);

快排的终止代码:

if (arr.length <= 1) {
  return arr;
}

函数返回和参数:

return quickSort(left).concat([pivot], quickSort(right))

其实函数返回和参数是最不好理解的。


健儿
79 声望4 粉丝

掌握好原生js。