代码随想录算法训练营补打卡 day14 |递归遍历、迭代遍历 、 统一迭代

递归遍历

思路

递归三要素:
1、函数参数和返回值
2、终止条件
3、单层递归逻辑

前中后序指的其实是跟节点的位置,前序:根左右,中序:左根右,后序:左右根。
遍历过程中,对根的操作实际上就是 本次要得到的节点的元素值。

前序遍历

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result =new ArrayList<Integer>();
        preorder(root,result);
        return result;

    }

    public void preorder(TreeNode cur,List<Integer> result){
        if(cur == null) return;
        result.add(cur.val);
        preorder(cur.left,result);
        preorder(cur.right,result);
    }
}


中序遍历

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result =new ArrayList<Integer>();
        inorder(root,result);
        return result;

    }

    public void inorder(TreeNode cur,List<Integer> result){
        if(cur == null) return;
        
        inorder(cur.left,result);
        result.add(cur.val);
        inorder(cur.right,result);
        
    }
}

后序遍历

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result =new ArrayList<Integer>();
        postorder(root,result);
        return result;

    }

    public void postorder(TreeNode cur,List<Integer> result){
        if(cur == null) return;
        
        postorder(cur.left,result);
        postorder(cur.right,result);
        result.add(cur.val);
    }
}


迭代遍历

思路

用栈实现二叉树的前中后序遍历。
本质上递归也是用栈实现的。
从时间复杂度上其实迭代法和递归法差不多(在不考虑函数调用开销和函数调用产生的堆栈开销),但是空间复杂度上,递归开销会大一些,因为递归需要系统堆栈存参数返回值等等。
递归更容易让程序员理解,但收敛不好,容易栈溢出。
这么说吧,递归是方便了程序员,难为了机器(各种保存参数,各种进栈出栈)。
在实际项目开发的过程中我们是要尽量避免递归!因为项目代码参数、调用关系都比较复杂,不容易控制递归深度,甚至会栈溢出。

前序和后序的迭代遍历 比较好理解
前序:因为需要中左右,所以先把右压入,再把左压入,这样弹出的时候就是中左右了。
后续:中右左,所以先把左压入,再把右压入,然后翻转,就是左右中了。

在迭代的过程中:有两个操作:
1、处理:将元素放进result数组中
2、访问:遍历节点
它们要访问的元素和处理的元素顺序是一样的,都是中间节点。
当栈不为空的时候,就表示还没有访问完

而中序遍历会比较特殊,因为要访问的元素和要处理的元素顺序是不一样的,
左中右,先达到二叉树左面最底部,再处理元素。
所以需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。

前序遍历

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null){
            return result;
        }
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.pop();
            result.add(node.val);
            if (node.right != null){
                stack.push(node.right);
            }
            if (node.left != null){
                stack.push(node.left);
            }
        }
        return result;
    }
}

后序遍历

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null){
            return result;
        }
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.pop();
            result.add(node.val);
            if (node.left != null){
                stack.push(node.left);
            }
            if (node.right != null){
                stack.push(node.right);
            }
        }
        Collections.reverse(result);
        return result;
    }
}

中序遍历

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null){
            return result;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()){
           if (cur != null){
               stack.push(cur);
               cur = cur.left;
           }else{
               cur = stack.pop();
               result.add(cur.val);
               cur = cur.right;
           }
        }
        return result;
    }
}

统一迭代

思路

题解思路:
把堆节点的访问和对节点的处理分开,给要处理的中间节点后加一个null标记一起压入栈,只有遇到了null标记,才处理。这样,只要遇到了空节点,就表示下面一个节点是要处理的节点。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值