遍历二叉树递归与迭代汇总,套路就是这么简单

递归与迭代的稍讲解

递归递归,先递进再归来。要做递归现在清楚递归每一步要做什么,以及递归的终止条件和入口参数。迭代的前提要清楚你要遍历的实体的结构,然后在遍历每一个点,在二叉树的迭代遍历中,迭代模仿了递归的工作方式,用栈存储了每个结点,直到将叶子结点进栈之后,才不断出栈,然后访问结点。

二叉树前序遍历

递归实现

存在子结点,就调用自身往下一层,不存在返回空。

var preorderTraversal = function(root) {
    let result = [];
    function visit(root){ //递归函数
        if(!root){
            return null;
        }
        result.push(root.val);
        if(root.left) visit(root.left);
        if(root.right) visit(root.right);
    }
    visit(root);
    return result;
};
迭代实现

前序遍历的迭代很好实现,按照先根后左右结点的方式,我们可以从上往下遍历,用栈存储结点,根据栈先进后出的原则,我们要先访问左结点,进栈的时候就得右结点先进栈, 然后就是将根结点出栈,再将他的子节点进栈。

var preorderTraversal2 = function(root){
    const result = [];
    if(!root){
        return result;
    }
    let stack = [];
    stack.push(root);
    while(stack.length){
        const root = stack.pop();
        result.push(root.val);
        if(root.right) stack.push(root.right);
        if(root.left) stack.push(root.left);
    }
    return result;
}

leetcode二叉树前序遍历题目

二叉树中序遍历

递归

递归和上边前序遍历的一模一样,区别在于访问结点的时候

var inorderTraversal = function(root) {
    let result = [];
    function visit(root){
        if(!root){
            return null;
        }
        if(root.left) visit(root.left);
        result.push(root.val);
        if(root.right) visit(root.right);
    }
    visit(root);
    return result;
};
迭代

迭代思想就是一直往左深度遍历,用栈存储结点,当到达左子树最后一个左结点时,退栈访问该结点的右孩子,然后不断重复。

var inorderTraversal = function(root) {
    let result = [];
    let stack = [];
    stack.push(root);
    let myroot = root;
    while(stack.length){
        while(myroot){
            myroot = myroot.left;
            stack.push(myroot);
        }
        stack.pop();
        if(stack.length){
            myroot = stack.pop();
            result.push(myroot.val);
            myroot = myroot.right;
            stack.push(myroot);
        }
    }
    return result;
};

二叉树后序遍历

递归

如上文。

迭代

后序遍历的迭代比较麻烦,主要在于如何记录这个结点左右孩子访问完毕,退栈方式和上面有所不同,当这个结点时叶子结点或是该结点左右孩子都访问过了就退栈。

var postorderTraversal = function(root) {
    if (!root) {
        return [];
    }
    const stack = []; // 记录结点和结点是否访问完全的标识。
    const result = [];
    stack.push({root, tag: false});
    let myroot = root;
    while (stack.length) {
        //一直往左,直至最后一个左结点
        while(myroot) {
            myroot = myroot.left;
            stack.push({ root: myroot, tag: false });
        }
        stack.pop(); //空值或返回上一层结点退栈。
        if (stack.length) {
            //取最后一个,当他是叶子结点,或者是遍历完子结点的根结点,就退栈
            const obj = stack[stack.length - 1];
            myroot = obj.root.right;
            if (!myroot || obj.tag) {
                result.push(obj.root.val);
                myroot = null; //指针置空,该结点左右孩子访问完毕
            } else {
                obj.tag = true;
                stack.push({ root: myroot, tag: false });
            }

        }
    }
    return result;
};
总结

递归就调用自身函数,入口传参就是左右孩子结点,当结点不存在的时候return空,递归结束。迭代就用栈存储孩子结点,遍历栈来访问结点。

声明:作者处于菜鸟阶段,还在不断学习,代码与思想仅供参考,欢迎指正。

复杂事往简单了去想,是拆解,是切割,就像一剑破万法,而将简单事往复杂了去想,是缝补,是搭建,是打造小天地。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值