如何用纯JS自顶向下将仅含children的树形结构转为叶节点路径数组
嘿,我来帮你搞定这个生成叶节点路径的问题!你当前的代码不管是迭代版还是递归版,都只是把所有节点的item值扁平地塞进了一个数组里,没做到追踪从根到每个叶子的完整路径对吧?下面我给你两种自顶向下的纯JS实现,完全符合你的要求——不依赖任何辅助方法,遍历过程中逐步构建路径数组。
核心思路
自顶向下的关键在于:遍历每个节点时,都要带着「从根节点到当前节点的路径」。每进入一个节点,就把它的item加入当前路径;如果遇到没有子节点的叶节点,就把这条完整路径存入结果数组中。
递归实现(更直观)
递归写法天然适合树形结构的自顶向下遍历,我们可以用内部函数来传递当前路径:
function getLeafPaths(node) { const result = []; // 内部递归函数,负责带着当前路径遍历节点 function traverse(currentNode, currentPath) { // 生成新路径(用扩展运算符避免修改原路径数组,保证每条路径独立) const updatedPath = [...currentPath, currentNode.item]; // 是叶节点?把当前完整路径加入结果 if (currentNode.children.length === 0) { result.push(updatedPath); return; } // 不是叶节点,遍历所有子节点,传递更新后的路径 currentNode.children.forEach(child => { traverse(child, updatedPath); }); } // 从根节点开始,初始路径为空数组 traverse(node, []); return result; }
代码解释
- 内部的
traverse函数接收两个参数:当前遍历的节点,以及从根到当前节点的路径。 - 每次进入节点都会生成新的路径数组(避免引用类型的修改导致路径混乱)。
- 遇到叶节点(
children为空数组)时,直接把路径存入结果;否则继续递归遍历所有子节点。
迭代实现(用栈模拟递归)
如果不想用递归,我们可以用栈来模拟自顶向下的遍历,栈中存储的不再是单个节点,而是「当前节点 + 对应路径」的组合:
function getLeafPathsIterative(node) { const result = []; // 栈元素是包含当前节点和当前路径的对象 const stack = [{ currentNode: node, currentPath: [] }]; while (stack.length > 0) { const { currentNode, currentPath } = stack.pop(); const updatedPath = [...currentPath, currentNode.item]; // 叶节点,存入完整路径 if (currentNode.children.length === 0) { result.push(updatedPath); continue; } // 注意:栈是后进先出,为了保持和递归一致的从左到右遍历顺序,需要反转子节点数组 [...currentNode.children].reverse().forEach(child => { stack.push({ currentNode: child, currentPath: updatedPath }); }); } return result; }
代码解释
- 栈中的每个元素都保存了当前节点和对应的路径,确保遍历过程中路径不会丢失。
- 弹出栈元素后生成新路径,判断是否为叶节点:是则存结果,否则将子节点反转后推入栈(保证遍历顺序和递归一致)。
你现有代码的问题分析
aggregateNodes(迭代版):只是用栈遍历所有节点,把item依次推入同一个数组,没有追踪每条路径的上下文,结果是扁平的,不是二维路径数组。aggregateNodesRecursive(递归版):嵌套forEach只处理了两层子节点,递归调用没有传递路径信息,而且所有item都推入同一个数组,导致结果混乱且不完整。
测试示例数据
把你提供的示例节点传入上述函数,比如:
var node = { item: 1, children: [ { item: 2, children: [ { item: 3, children: [ { item: 4, children: [] }, { item: 5, children: [] }, { item: 6, children: [ { item: 7, children: [] }, { item: 8, children: [] }, { item: 9, children: [] } ] } ] }, { item: 10, children: [ { item: 11, children: [] }, { item: 12, children: [ { item: 13, children: [] }, { item: 14, children: [] } ] } ] } ] } ] }; console.log(getLeafPaths(node));
就能得到你期望的二维路径数组:
[ [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 3, 6, 7], [1, 2, 3, 6, 8], [1, 2, 3, 6, 9], [1, 2, 10, 11], [1, 2, 10, 12, 13], [1, 2, 10, 12, 14] ]
内容的提问来源于stack exchange,提问作者Lance Pollard
相关产品推荐
相关产品推荐

