二叉树中序遍历函数异常:左分支返回[3]而非[]的原因问询
二叉树中序遍历递归函数问题解析
问题背景
实现二叉树中序遍历递归函数,输入树结构[1,null,2,3](根节点1,左子树为空,右子节点2的左子树为3),预期输出[1,3,2],但原函数实际输出[3,1,3,2]。从日志可见根节点1的左分支返回了[3](预期应为[]);调整函数操作顺序后结果正确,但日志里左分支仍显示返回[3],以下是两个现象的具体解释:
原函数代码
/** * Definition for a binary tree node. * function TreeNode(val, left, right) { * this.val = (val===undefined ? 0 : val) * this.left = (left===undefined ? null : left) * this.right = (right===undefined ? null : right) * } */ /** * @param {TreeNode} root * @return {number[]} */ var inorderTraversal = function(root,typ, par) { let result = [] ; console.log(`side = ${typ} currentVal = ${root? root.val: 'no root'}`,root) if (!root) return [] left = inorderTraversal(root.left, 'left', root.val) right = inorderTraversal(root.right, 'right', root.val ) console.log(`side = ${typ} currentVal = ${root? root.val: 'no root'} parent = ${par}`,root) console.log(`${root.val}-left, and parent= ${par}`, left) console.log(`${root.val}-rigth, and parent= ${par}`, right) result = [...left, root.val, ...right ]; console.log('res', result) return result };
修改后函数代码
var inorderTraversal = function(root,typ, par) { let result = [] ; console.log(`side = ${typ} currentVal = ${root? root.val: 'no root'}`,root) if (!root) return [] left = inorderTraversal(root.left, 'left', root.val) //modifying result before traversing right result = [...left, root.val] right = inorderTraversal(root.right, 'right', root.val ) console.log(`side = ${typ} currentVal = ${root? root.val: 'no root'} parent = ${par}`,root) console.log(`${root.val}-left, and parent= ${par}`, left) console.log(`${root.val}-rigth, and parent= ${par}`, right) result = [...result, ...right ]; console.log('res', result) return result };
日志输出
side = undefined currentVal = 1 [1,null,2,3] side = left currentVal = no root null side = right currentVal = 2 [2,3] side = left currentVal = 3 [3] side = left currentVal = no root null side = right currentVal = no root null side = left currentVal = 3 parent = 2 [3] 3-left, and parent= 2 [] 3-rigth, and parent= 2 [] res [ 3 ] side = right currentVal = no root null side = right currentVal = 2 parent = 1 [2,3] 2-left, and parent= 1 [ 3 ] 2-rigth, and parent= 1 [] res [ 3, 2 ] side = undefined currentVal = 1 parent = undefined [1,null,2,3] 1-left, and parent= undefined [ 3 ] 1-rigth, and parent= undefined [ 3, 2 ] res [ 3, 1, 3, 2 ]
现象1:原函数根节点左分支返回[3]且结果错误
核心问题是**left和right变量未用let/const声明,变成了全局变量**,递归调用时会被后续操作覆盖:
- 根节点1先调用左子树(null),返回
[],此时全局left = []。 - 接着根节点1调用右子树2,进入2的递归流程:
- 2调用左子树3,3的递归会把全局
left重新赋值为自身左子树返回的[],最终3的结果是[3],并把全局left覆盖为[3]。 - 2调用右子树(null)后,结果为
[3,2]返回给根节点1的right。
- 2调用左子树3,3的递归会把全局
- 回到根节点1的递归时,全局
left已经被3的递归覆盖为[3](而非最初左子树返回的[]),因此最终结果变成[3,1,3,2],完全错误。日志里显示的[3]是被覆盖后的全局变量值,不是根节点左子树实际返回的结果。
现象2:修改后函数结果正确,但日志仍显示左分支返回[3]
修改后的函数调整了操作顺序,在调用右子树前就保存了正确的中间结果:
- 根节点1调用左子树(null)返回
[]后,立刻执行result = [...[],1] = [1],把左分支结果+当前节点值固定下来。 - 后续调用右子树时,即使全局
left被覆盖为[3],但根节点1的result已经保存了正确的初始值,最后只需要追加右子树的[3,2],就能得到正确结果[1,3,2]。 - 日志里打印的
left = [3],是因为打印操作在调用完右子树之后执行,此时全局left已经被右子树的递归流程覆盖,打印的是覆盖后的值,而非根节点左子树最初返回的[]。
彻底解决方法
给left和right加上const声明,让它们成为函数局部变量,避免递归调用互相干扰:
var inorderTraversal = function(root, typ, par) { let result = []; console.log(`side = ${typ} currentVal = ${root? root.val: 'no root'}`, root); if (!root) return []; // 声明局部变量,避免全局污染 const left = inorderTraversal(root.left, 'left', root.val); const right = inorderTraversal(root.right, 'right', root.val); console.log(`side = ${typ} currentVal = ${root? root.val: 'no root'} parent = ${par}`, root); console.log(`${root.val}-left, and parent= ${par}`, left); console.log(`${root.val}-rigth, and parent= ${par}`, right); result = [...left, root.val, ...right]; console.log('res', result); return result; };
内容的提问来源于stack exchange,提问作者krickht
相关产品推荐
相关产品推荐

