SOURCE

// 思路
// 二叉树性质有点像单链表 只能通过父节点 找到 子节点 而不能反向找父节点
// 因此当前节点无法判断自身是否为左叶子 必须通过 父节点 才能判断 并采集

class Node {
    constructor(value, left, right) {
        this.value = value;
        this.left = left;
        this.right = right;
    }
}

let n1 = new Node(1, null, null);
let n2 = new Node(2, null, null);
let n4 = new Node(4, n1, n2);
let n6 = new Node(6, null, null);
let root = new Node(5, n4, n6);

// 递归实现
function fn(node) {
    // 因为只计算左叶子节点 因此要先求左右子树的结果 这种情况就适用 后序遍历
    let 左子树累计值 = 0
    // 虽然本例代码不算简洁 但是通过父节点过滤掉了 空节点 和 不必要节点 的递归 性能要更好
    if (node.left) {
        // 有左孩子
        if (node.left.left == null && node.left.right == null) {
            // 左孩子为叶子节点 则记录值
            左子树累计值 = node.left.value
        } else {
            // 不是叶子节点 则继续递归
            左子树累计值 = fn(node.left)
        }
    }
    let 右子树累计值 = 0
    if (node.right && (node.right.left || node.right.right)) {
        // 有右孩子 且 不是叶子节点 则继续递归
        右子树累计值 = fn(node.right)
    }
    // 递归出口
    return 左子树累计值 + 右子树累计值
}

// 验证
console.log('递归求和:' + fn(root)) // 1

// 层序遍历
function fn2(root) {
    let result = 0
    let queue = [] // 辅助队列
    queue.push(root)
    while (queue.length) {
        // 注 层序遍历不是非得 let size = queue.length while(size--)
        // 当需要按层划分运算时 为了区分每一层 才这样做
        // 只为了遍历的话 一边遍历一边往队列末尾添加元素就行
        let node = queue.shift()
        if (node.left) {
            // 有左孩子
            if (node.left.left == null && node.left.right == null) {
                // 左孩子是叶子节点 统计值 并且不对其遍历
                result += node.left.value
            } else {
                // 不是叶子节点 装入队列进行遍历
                queue.push(node.left)
            }
        }
        // 右孩子存在 装入队列遍历
        node.right && queue.push(node.right)
    }
    return result
}

// 验证
console.log('层序遍历求和:' + fn2(root)) // 1
console 命令行工具 X clear

                    
>
console