写给所有人看的前端算法讲解———二叉树遍历问题

259 阅读2分钟

二叉树遍历问题

image.png

一、DFS深度优先遍历

诀窍:先扎到尽头,再处理数值。整个root的问题,细化到最小子树来解决。

image.png

1.1 DFS三种顺序的递归遍历

image.png

1.1.1 前序遍历:中->左->右
function DFS(root){
    let res = []
    function DFS_first(root){
        if(!root) return //递归的终止条件
        
        res.push(root.val) //每层递归的处理语句,先存储当前的值
        DFS_first(root.left) //后挖掘左节点,一直挖到底
        DFS_first(root.right)  //左节点触底后,开始挖掘右节点
    }
}
1.1.2 中序遍历:左->中->右
function DFS(root){
    let res = []
    function DFS_in(root){
        if(!root) return //递归的终止条件
        
        DFS_first(root.left) //先挖掘左节点,一直挖到底
        res.push(root.val) //到底之后,存储当前的值
        DFS_first(root.right)  //继续挖掘右节点
    }
}
1.1.3 后序遍历:左->右->中
function DFS(root){
    let res = []
    function DFS_in(root){
        if(!root) return //递归的终止条件
        
        DFS_first(root.left) //先挖掘左节点,一直挖到底
        DFS_first(root.right)  //继续挖掘右节点
        res.push(root.val) //到底之后,存储当前的值
    }
}
1.2 DFS三种顺序的迭代遍历
1.2.1 前序遍历:中->左->右 入栈就要先右后左
function DFS_first(root){
    let res = [] 
    let stack = []
    stack.push(root)
    while(stack.length){
        let node = stack.pop()
        res.push(node.val)
        node.right && stack.push(node.right)
        node.left && stack.push(node.left)
        
    }
    return res
}
1.2.2 中序遍历:左->中->右(根节点没有立刻处理,需要指针)
function DFS_in(root){
    let res = [] 
    let stack = []
    let cur = root
    while(stack.length || cur){
        if(cur){ //先把左边缘的节点push到stack
            stack.push(cur)
            cur = cur.left
        }else{ //cur指向最底部的左节点的空左子节点,cur = null
            let node = stack.pop()
            res.push(node.val)
            cur = node.right //cur指向最底部的左节点的空右子节点,cur = null
        }

    }
    return res
}
1.2.3 后序遍历:左->右->中(将前序遍历左右掉转再整体翻转)
function DFS_back(root){
    let res = [] 
    let stack = []
    while(stack.length){
        let node = stack.pop()
        res.push(node.val)
        node.left && stack.push(node.left)
        node.right && stack.push(node.right)
    }
    return res.reverse()
}

二、BFS广度优先遍历(维护一个stack)

逐层遍历,先水平探索,后深入发展。 ps:跟DFS的前序递归遍历很像,多了for循环,并且使用了shift。

image.png

function BFS(root){
    let stack = [root]
    let res = []
    while(stack.length){
        let len = stack.length
        for(let i = 0;i<len;i++){ //借助for水平遍历
            let node = stack.shift()
            res.push(node.val)
            node.left && stack.push(node.left)
            node.right && stack.push(node.right)
        }
    }
    return res
}

三、小结

此时,我们已经学习了二叉树遍历的7种方法:

  • 6种DFS深度优先遍历方法,包括3种顺序(前序、中序、后序)*2种方法(递归和迭代)。
  • 1种BFS广度优先遍历方法(迭代)。

其中,DFS三种递归方法结构相同,关键语句顺序不同,可以立马举一反三。DFS三种迭代方法,前序与后序相似,后序是前序的左右翻转再整体reverse,中序迭代则是较为复杂。BFS与DFS的前序迭代遍历十分相似,但是增加了for循环进行同层遍历,并且推荐使用shift。