二叉树的遍历算法(前中后+层次遍历)的递归和迭代写法

文章概述

介绍了二叉树的4种遍历算法,每一种都用递归和迭代完成。

题目链接

二叉树的前序遍历
二叉树的中序遍历
二叉树的后序遍历
二叉树的层序遍历

递归遍历

前中后序的递归遍历比较简单,就是按照不同的遍历顺序依次写就可以。
前序遍历:

  private static void postTravel(TreeNode root, ArrayList<Integer> list) {
    if(root == null){
        return;
    }
    list.add(root.val);
    if(root.left!=null) postTravel(root.left,list);
    if(root.right!=null) postTravel(root.right,list);
}

中序遍历

  private static void postTravel(TreeNode root, ArrayList<Integer> list) {
    if(root == null){
        return;
    }
    if(root.left!=null) postTravel(root.left,list);
     list.add(root.val);
    if(root.right!=null) postTravel(root.right,list);
}

后序遍历

private static void postTravel(TreeNode root, ArrayList<Integer> list) {
    if(root == null){
        return;
    }
    if(root.left!=null) postTravel(root.left,list);
    if(root.right!=null) postTravel(root.right,list);
    list.add(root.val);
}

迭代遍历

迭代遍历是利用栈先进后出的特点,前序遍历是中左右,每次先把中间节点计入结果,然后将右孩子入栈,再将左孩子入栈,得到的结果就是中左。

    public List<Integer> preorderTraversal(TreeNode root) {
        ArrayList<Integer> res = new ArrayList<>();
        //前序是中左右
        Stack<TreeNode> stack = new Stack<>();
        if(root == null) return res;
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode pop = stack.pop();
            res.add(pop.val);
            if(pop.right!=null){
                stack.push(pop.right);
            }
            if(pop.left!=null){
                stack.push(pop.left);
            }
        }
        return res;
    }

后序遍历可以参考前序遍历,后序遍历是左右中,可以先得到中右左,再翻转。因为得到中间节点比较简单。

    public List<Integer> postorderTraversal(TreeNode root) {
 //迭代写法:
        //后序遍历是左右中,可以做一个中右左,再倒序
        ArrayList<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root == null) return res;
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode pop = stack.pop();
            res.add(pop.val);
            if(pop.left!=null){
                stack.push(pop.left);
            }
            if(pop.right!=null){
                stack.push(pop.right);
            }
        }
        Collections.reverse(res);
        return res;
    }

中序遍历的思想就是一直看左边,左边没有了就将节点读取,并将右孩子节点加入,手动模拟也是这样的步骤。

public List<Integer> inorderTraversal(TreeNode root) {
   //顺序是左中右
        ArrayList<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
//        stack.push(root);
        TreeNode cur = root;
        while (cur!=null || !stack.isEmpty()){
            if(cur !=null){
//                先看左边,有的话就加入
                stack.push(cur);
                cur=cur.left;
            }
            else {
                //左边都没了的情况下,标记并开始看右边。
                cur = stack.pop();
                res.add(cur.val);
                cur=cur.right;

            }
        }
        return res;
    }

迭代的统一写法

因为中序遍历有一点不同,所以记起来比较难,所以用一种统一的写法会方便记忆。
也是用的栈的思想,但是不同的是在中间节点用一个null来代替。
统一格式
while(){
if(!=null){}
else{}
}
前序遍历:

//前序遍历的统一写法
public List<Integer> preTraversalAll(TreeNode root){
    ArrayList<Integer> res = new ArrayList<>();
    Stack<TreeNode> stack = new Stack<>();
    if(root == null){
        return res;
    }
    stack.push(root);
    while (!stack.isEmpty()){
        TreeNode node  = stack.peek();
        if(node != null){
            //前序
            //前序是中左右,入栈就是右左中
            stack.pop();//这个点要弹出
            if(node.right!=null){
                stack.push(node.right);
            }
            if(node.left !=null){
                stack.push(node.left);
            }
            stack.push(node);
            stack.push(null);
        }else {
            stack.pop();
            TreeNode tp = stack.pop();
            res.add(tp.val);
        }
    }
    return res;
}

中序遍历:

  public List<Integer> inorderTraversalAll(TreeNode root){
        ArrayList<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root == null){
            return res;
        }
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node  = stack.peek();
            if(node != null){
                //中序
                //左中右,右中左
                stack.pop();//这个点要弹出
                if(node.right!=null){
                    stack.push(node.right);
                }

            stack.push(node);
            stack.push(null);
                if(node.left !=null) {
                    stack.push(node.left);
                }
            }else {
                stack.pop();
                TreeNode tp = stack.pop();
                res.add(tp.val);
            }
        }
        return res;
    }

后序遍历:

  public List<Integer> postTraversalAll(TreeNode root){
        ArrayList<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root == null){
            return res;
        }
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node  = stack.peek();
            if(node != null){
                //后序
                //左右中,变成中右左
                stack.pop();//这个点要弹出
                stack.push(node);
                stack.push(null);
                if(node.right!=null){
                    stack.push(node.right);
                }
                if(node.left !=null) {
                    stack.push(node.left);
                }
            }else {
                stack.pop();
                TreeNode tp = stack.pop();
                res.add(tp.val);
            }
        }
        return res;
    }

}

层次遍历

1.递归写法
DFS的思想

private static  void  dfsLevelOrder(TreeNode node,int depth,List<List<Integer>> res){
        if (node == null){
            return;
        }
        depth++;
        //新的一层,创建一个新的list
        if(res.size()<depth){
            ArrayList<Integer> list = new ArrayList<>();
            res .add(list);
        }
		//还是该层,添加元素将即可
        res.get(depth-1).add(node.val);
        //递归调用
        dfsLevelOrder(node.left,depth,res);
        dfsLevelOrder(node.right,depth,res);
    }
  1. 迭代写法
    利用队列先进先出的特性实现,先记录当前队列的长度n,也就是该层有几个元素,然后依次出队,因为队列中的前n个元素就是该层的元素。然后将所有左右孩子入队,再次记录长度。
public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue= new LinkedList<>();
        List<List<Integer>> res  = new ArrayList<>();
        if(root == null){
            return res;
        }
        queue.offer(root);
        while (!queue.isEmpty()){
            List<Integer> list = new ArrayList<>();
            int len = queue.size()-1;
            while (len>=0){
                TreeNode poll = queue.poll();
                if(poll!=null) {
                    list.add(poll.val);
                    if (poll.left != null) {
                        queue.add(poll.left);
                    }
                    if (poll.right != null) {
                        queue.add(poll.right);
                    }
                }
                len--;
            }
            res.add(list);
        }
        return res;
    }

参考

代码随想录

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值