day14 | 二叉树的遍历

在这里插入图片描述

二叉树的遍历

深度遍历

前序遍历

递归实现

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        preorder(root,res);
        return res;
    }
    public void preorder(TreeNode root,List<Integer> res){
        if(root == null){
            return;
        }
        res.add(root.val);
        preorder(root.left,res);
        preorder(root.right,res);
    }

迭代实现
实现思路:
使用栈模拟递归。

  1. 栈中压入要处理的节点,弹出要处理的节点,并将要处理的节点值加入数组中
  2. 判断处理节点的右孩子和左孩子是否存在,存在依次将右孩子和左孩子压栈;若左右孩子不存在,则继续弹出栈顶元素,
  3. 继续上述操作,直到栈空为止
    实现过程:
public List<Integer> preorderTraversal1(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root == null){
            return res;
        }
        stack.push(root);
        TreeNode cur = new TreeNode();
        while(!stack.empty()){
            cur = stack.pop();
            res.add(cur.val);
            //右孩子先入栈,左孩子后入栈
            if(cur.right!=null){
                stack.push(cur.right);
            }
            if(cur.left!=null){
                stack.push(cur.left);
            }
        }
        return res;
    }
中序遍历

递归实现

public static List<Integer> inOrderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        inOrder(root, res);
        return res;
    }

    public static void inOrder(TreeNode root, List<Integer> res) {
        if (root == null) {
            return;
        }
        inOrder(root.left, res);
        res.add(root.val);
        inOrder(root.right, res);
    }

迭代实现
实现思路:

  1. 根节点不为空时入栈
  2. 判断当前节点的左孩子是否为空,左孩子不为空,左孩子入栈;左孩子为空时进行第三步
  3. 当前节点出栈,并将当前节点值存入数组中
  4. 判断当前节点的右孩子是否为空,右孩子不为空,右孩子入栈,然后重复第二步;右孩子为空,重复第三步
    实现过程:
public static List<Integer> inOrderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while (cur != null || !stack.empty()) {
            //入栈当前节点并判断当前节点的左孩子是否为空,不为空,入栈
            if (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            //左孩子为空,处理栈顶元素,并判断右孩子是否为空,不为空进入if中的语句,判断右孩子的左孩子是否为空
            //右孩子为空,进入else,栈顶元素出栈,并进行处理
            else{
                cur = stack.pop();
                res.add(cur.val);
                cur = cur.right;
            }
        }
        return res;
    }
后序遍历

递归实现

public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        postOrder(root, res);
        return res;
    }

    public void postOrder(TreeNode root, List<Integer> res) {
        if (root == null) {
            return;
        }
        postOrder(root.left, res);
        postOrder(root.right, res);
        res.add(root.val);
    }

迭代实现
实现思路:将前序遍历的迭代法中第二部步交换左孩子和右孩子的入栈顺序,然后将整个数组反转即可

  1. 栈中压入要处理的节点,弹出要处理的节点,并将要处理的节点值加入数组中
  2. 判断处理节点的右孩子和左孩子是否存在,存在依次将左孩子和右孩子压栈;若左右孩子不存在,则继续弹出栈顶元素,
  3. 继续上述操作,直到栈空为止
  4. 反转整个数组

实现过程:

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

深度遍历的统一格式

我们以中序遍历为例,在二叉树中递归能做的,栈也能做! 但使用栈的话,无法同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况。
那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。
如何标记呢,就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记。 这种方法也可以叫做标记法

前序遍历

遍历顺序:右左中

 //前序遍历
    public static List<Integer> preOrder(TreeNode root){
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if (root == null) {
            return res;
        }
        stack.push(root);
        while(!stack.empty()){
            TreeNode cur = stack.peek();
            if(cur!=null){
                stack.pop();// 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
                if(cur.right!=null){// 添加右节点(空节点不入栈)
                    stack.push(cur.right);
                }
                if(cur.left!=null){//添加左节点(空节点不入栈)
                    stack.push(cur.left);
                }
                stack.push(cur);//添加中节点,且为要处理的节点
                stack.push(null);//标记要处理的节点
            }
            else{// 只有遇到空节点的时候,才将下一个节点放进结果集
                stack.pop();//弹出空节点
                cur = stack.pop();//重新获取要处理的节点
                res.add(cur.val);//将要处理的节点值加入数组中
            }
        }
        return res;
    }
中序遍历

遍历顺序:右中左

public static List<Integer> inOrder(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if (root == null) {
            return res;
        }
        stack.push(root);
        while(!stack.empty()){
            TreeNode cur = stack.peek();
            if(cur!=null){
                stack.pop();// 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
                if(cur.right!=null){// 添加右节点(空节点不入栈)
                    stack.push(cur.right);
                }
                stack.push(cur);//添加中节点,且为要处理的节点
                stack.push(null);//标记要处理的节点
                if(cur.left!=null){//添加左节点(空节点不入栈)
                    stack.push(cur.left);
                }
            }
            else{// 只有遇到空节点的时候,才将下一个节点放进结果集
                stack.pop();//弹出空节点
                cur = stack.pop();//重新获取要处理的节点
                res.add(cur.val);//将要处理的节点值加入数组中
            }
        }
        return res;
    }
后序遍历

遍历顺序:中右左

public static  List<Integer> postOrder(TreeNode root){
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if (root == null) {
            return res;
        }
        stack.push(root);
        while(!stack.empty()){
            TreeNode cur = stack.peek();
            if(cur != null){
                stack.pop();// 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
               stack.push(cur);//添加中节点,且为要处理的节点
                stack.push(null);//标记要处理的节点
                 if(cur.right!=null){// 添加右节点(空节点不入栈)
                    stack.push(cur.right);
                }
                 if(cur.left!=null){//添加左节点(空节点不入栈)
                    stack.push(cur.left);
                }
            }
           else{// 只有遇到空节点的时候,才将下一个节点放进结果集
                stack.pop();//弹出空节点
                cur = stack.pop();//重新获取要处理的节点
                res.add(cur.val);//将要处理的节点值加入数组中
            }
        }
        return res;
    }

广度遍历

迭代法遍历二叉树实现层次遍历
实现思路:
使用队列存储要遍历的节点

  1. 根节点不为空,入队
  2. 队列不空进入循环
  3. 记录当前队列长度
  4. 使用第三步记录的队列长度记录遍历本层节点的次数,遍历本层节点思路如下:
    1. 将当前节点值加入数组中
    2. 判断左节点是否为空,不为空入栈
    3. 判断右节点是否为空,不为空入栈
    4. 当前层节点数减一(之前记录的队长减一)
      实现过程:
public static List<List<Integer>> levelOrder(TreeNode root){
        List<List<Integer>> res = new ArrayList<>();
        Queue<TreeNode> que = new ArrayDeque<>();
        if(root == null){
            return  res;
        }
        que.offer(root);
        int size = 0;
        while(!que.isEmpty()){
            List<Integer> list = new ArrayList<>();
            size = que.size();
            while(size>0){
                TreeNode cur = que.poll();
                list.add(cur.val);
                if(cur.left!=null){
                    que.offer(cur.left);
                }
                if(cur.right!=null){
                    que.offer(cur.right);
                }
                size--;
            }
            res.add(list);

        }
        return res;
    }
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值