JavaScript实现二叉树的构建、广度优先遍历BFT(层序)和深度优先遍历DFT(前中后序)

180 阅读1分钟
1.二叉树的构建
// 定义二叉树的节点
function TreeNode(val, left, right) {
    this.val = val === undefined ? 0 : val
    this.left = left === undefined ? null : left
    this.right = right === undefined ? null : right
}
// 定义二叉树的构造函数
function CompleteBinaryTree() { }
// 原型方法1:根据层序遍历构建二叉树
CompleteBinaryTree.prototype.buildTree = function (arr) {
    var len = arr.length
    if (len === 0) return null
    var root = new TreeNode(arr[0]) // 定义根节点
    if (len === 1) return root
    var queue = [root] // 定义一个队列用于存放需要添加左右节点的子节点
    var curRoot = null // 定义当前需要被添加左右子节点的节点

    // 遍历queue,得到当前需要被添加左右子节点的节点
    for (var i = 0; i < queue.length; i++) {
        curRoot = queue[i]
        // 1.当前节点有左节点(根据数组长度判断)
        if (2 * i + 1 < len) {
            // 左节点为空
            if (arr[2 * i + 1] === null) {
                curRoot.left = null
            } else { // 左节点不为空
                curRoot.left = new TreeNode(arr[2 * i + 1])
                queue.push(curRoot.left) // 将左节点放进队列
            }
        }
        // 2.当前节点有右节点
        if (2 * i + 2 < len) {
            // 右节点为空
            if (arr[2 * i + 2] === null) {
                curRoot.right = null
            } else { // 右节点不为空
                curRoot.right = new TreeNode(arr[2 * i + 2])
                queue.push(curRoot.right) // 将右节点放进队列
            }
        }
    }
    return root
}
// 输入数据
var arr = [1, null, 2, 3, null, 4, null]
var myTree = new CompleteBinaryTree()
var root = myTree.buildTree(arr)
// console.log(root);
2.广度优先遍历BFT(层序)
// 原型方法2:广度优先遍历-层序遍历-LeetCode102
CompleteBinaryTree.prototype.levelOrder = function (root) {
    var result = [] // 最终的结果数组
    // 当root为空时
    if (root === null) return result

    var queue = [root] // 定义一个队列,用于存放当前层级的节点
    // 当队列中有元素
    while (queue.length) {
        var levelResult = [] // 每一层的结果数组(*循环一次需要清空)
        // 1.记录当前元素个数,进行遍历
        var len = queue.length
        var curNode = null
        for (var i = 0; i < len; i++) {
            curNode = queue.shift()
            levelResult.push(curNode.val)
            // 2.向队列中添加下一层级的节点
            // && 逻辑与,当表达式1为真,才会执行表达式2
            curNode.left && queue.push(curNode.left)
            curNode.right && queue.push(curNode.right)
        }
        // 3.把这一层的结果数组放到总结果的最后
        result.push(levelResult)
    }
    return result
}
console.log(myTree.levelOrder(root)); // [[1], [2], [3], [4]]
3.深度优先遍历DFT(序)
// 原型方法3:深度优先遍历-前序遍历-LeetCode144
CompleteBinaryTree.prototype.preOrderTraversal = function (root) {
    var result = []
    // 对当前节点进行处理
    var dfs = function (root) {
        if (root === null) return result
        result.push(root.val)
        dfs(root.left)
        dfs(root.right)
    }
    dfs(root)
    return result
}
console.log(myTree.preOrderTraversal(root)); // [1, 2, 3 ,4]

// 原型方法3:深度优先遍历-中序遍历-LeetCode94
CompleteBinaryTree.prototype.inOrderTraversal = function (root) {
    var result = []
    // 对当前节点进行处理
    var dfs = function (root) {
        if (root === null) return result
        dfs(root.left)
        result.push(root.val)
        dfs(root.right)
    }
    dfs(root)
    return result
}
console.log(myTree.inOrderTraversal(root)); // [1, 4, 3, 2]

// 原型方法4:深度优先遍历-后序遍历-LeetCode145
CompleteBinaryTree.prototype.postOrderTraversal = function (root) {
    var result = []
    // 对当前节点进行处理
    var dfs = function (root) {
        if (root === null) return result
        dfs(root.left)
        dfs(root.right)
        result.push(root.val)
    }
    dfs(root)
    return result
}
console.log(myTree.postOrderTraversal(root)); // [4, 3, 2, 1]

以上参考LeetCode题解 最后想提一个问题:层序遍历的结果和先序遍历的感觉是一样的?

(2021/8/17)自己解答:不一样,比如:[1, 2, null, 3, 4, 5],层序遍历的结果是[1, 2, 3, 4, 5];而先序遍历的结果是:[1, 2, 3, 5, 4];中序遍历的结果为[5, 3, 2, 4, 1];后序遍历的结果为[5, 3, 4, 2, 1]。

以及 使用const和let替换var