面试题答案
一键面试代码实现
function collectNodesInArray(root) {
const result = [];
const stack = [root];
while (stack.length > 0) {
const node = stack.pop();
result.push(node);
if (node.children) {
for (let i = node.children.length - 1; i >= 0; i--) {
stack.push(node.children[i]);
}
}
}
return result;
}
实现思路
- 初始化:首先初始化一个空数组
result
用于存储结果,以及一个栈stack
并将根节点root
压入栈中。 - 循环处理:通过
while
循环,只要栈不为空,就从栈中弹出一个节点。将弹出的节点添加到result
数组中。 - 处理子节点:检查弹出的节点是否有
children
属性,如果有,则将子节点逆序压入栈中。这是因为栈是后进先出(LIFO)的数据结构,逆序压入可以保证先处理深度更深的节点,符合深度优先遍历的要求。 - 返回结果:循环结束后,
result
数组中就按深度优先顺序包含了所有节点。
选择特定数组创建方法的原因
这里选择使用push
方法来向数组中添加元素。push
方法是JavaScript数组原生方法,具有较好的性能和广泛的兼容性。它在数组末尾添加元素,时间复杂度为O(1)(平均情况下),对于不断追加节点到结果数组的操作来说非常高效。
性能优化
- 减少内存分配:使用栈来模拟递归调用,避免了大量递归调用带来的栈溢出风险以及频繁的函数调用开销。在循环中复用栈空间,减少了不必要的内存分配。
- 减少不必要操作:在处理子节点时,直接逆序将子节点压入栈,避免了额外的数组转换操作(例如先将子节点转换为数组再逆序),减少了计算开销。
处理潜在内存问题
- 及时释放内存:通过栈的方式,当一个节点及其子节点都处理完毕后,栈中相应的空间会被释放,避免了内存的长期占用。
- 限制数据量:在实际应用中,如果数据量过大,可以考虑分批处理或者增加分页机制,避免一次性加载和处理过多数据导致内存溢出。