二叉树的遍历

二叉树的遍历

在这里插入图片描述

深度遍历

三种遍历最简单直接的方法就是递归,直接按照顺序编写。

前序遍历

根结点->左子树->右子树
上图遍历为12457836

  • 递归
public List<Integer> preorder(TreeNode root){

        List<Integer>reslist=new ArrayList<>();
        if (root==null)return reslist;
        preHelper(root,reslist);
        return reslist;

    }
    public void preHelper(TreeNode root,List<Integer>reslist){
        if (root!=null){
            reslist.add(root.val);
            if (root.left!=null){
                preHelper(root.left,reslist);
            }
            if (root.right!=null){
                preHelper(root.right,reslist);
            }
        }
    }
  • 迭代
    使用栈辅助存储。因为是根左右,而且栈是先进后出,所以每次弹出栈顶(记录)时,先把右子结点放入栈,再将左子结点入栈。这样,左子结点比右子结点先出栈。例如:
  1. 1入栈。栈:1
  2. 1出栈,右子结点3入栈,左2入栈。栈:23
  3. 2出栈,右5左4入栈,栈:453
  4. 4出栈,没有子结点,栈:53
  5. 5出栈,右8左7入栈,栈:783
  6. 7出栈,栈:83
  7. 8出栈,栈:3
  8. 3出栈,右6入栈,栈:6
  9. 6出栈,栈
  10. 因为栈空,所以结束。

顺序为栈弹出顺序。

public List<Integer> preorderIter(TreeNode root){
        List<Integer>reslist=new ArrayList<>();
        if (root==null)return reslist;
        Stack<TreeNode> s=new Stack<>();
        TreeNode cur=root;
        s.push(root);
        while (!s.isEmpty()){
            cur=s.pop();
            reslist.add(cur.val);
            if (cur.right!=null){
                s.push(cur.right);
            }
            if (cur.left!=null){
                s.push(cur.left);
            }
        }
        return reslist;
    }

中序遍历

左子树->根结点->右子树
上图遍历为42758136

  • 递归
public List<Integer> inorder(TreeNode root){

        List<Integer>reslist=new ArrayList<>();
        if (root==null)return reslist;
        inHelper(root,reslist);
        return reslist;

    }
    public void inHelper(TreeNode root,List<Integer>reslist){
        if (root!=null){
            if (root.left!=null){
                inHelper(root.left,reslist);
            }
            reslist.add(root.val);
            if (root.right!=null){
                inHelper(root.right,reslist);
            }
        }
    }
  • 迭代
public List<Integer> inorderIter(TreeNode root){
        List<Integer>reslist=new ArrayList<>();
        if (root==null)return reslist;
        Stack<TreeNode> s=new Stack<>();
        TreeNode cur=root;
        while (cur!=null||!s.isEmpty()){
            while (cur!=null){
                s.push(cur);
                cur=cur.left;
            }
            cur=s.pop();
            reslist.add(cur.val);
            cur=cur.right;
        }
        return reslist;
    }

使用栈辅助。先把所有左子结点入栈,然后弹出栈顶(记录),再将该结点右子结点入栈,循环。例如:

  1. 1入栈,2入栈,4入栈。栈:421
  2. 4出栈。栈:21
  3. 2出栈,右5入栈。栈:51
  4. 7入栈,栈:751
  5. 7出,栈:51
  6. 5出,8入,栈:81
  7. 8出,栈:1
    ……

后序遍历

左子树->右子树->根结点
上图遍历为47852631

  • 递归
public List<Integer> postorder(TreeNode root){
        List<Integer>reslist=new ArrayList<>();
        if (root==null)return reslist;
        postHelper(root,reslist);
        return reslist;

    }
    public void postHelper(TreeNode root,List<Integer>reslist){
        if (root!=null){
            if (root.left!=null){
                postHelper(root.left,reslist);
            }
            if (root.right!=null){
                postHelper(root.right,reslist);
            }
            reslist.add(root.val);
        }
    }
  • 迭代
    一种讨巧的方式。前序遍历是以根右左的方式入栈,出来的结果是根左右。所以后序遍历就可以以根左右的方式入栈,出来的结果是根右左。然后将结果翻转,就变成了左右根!
    public List<Integer> postorderIter(TreeNode root){
        List<Integer>reslist=new ArrayList<>();
        if (root==null)return reslist;
        Stack<TreeNode> s=new Stack<>();
        TreeNode cur=root;
        s.push(root);
        while (!s.isEmpty()){
            cur=s.pop();
            reslist.add(0,cur.val);
            if (cur.left!=null)s.push(cur.left);
            if (cur.right!=null)s.push(cur.right);
        }
        return reslist;
    }

例如:

  1. 根结点1入栈,栈:1
  2. 1弹出,1的左右子结点入栈,栈:32
  3. 3出栈,右6入栈,栈:62
  4. 6弹出,栈:2
  5. 2弹出,左右45入栈,栈:54
  6. 5弹出,左右78入栈,栈:874
  7. 8,7,4接连弹出,栈空

遍历即为栈弹出的相反顺序。

广度遍历(层次遍历)

这种遍历方式也就是一层一层遍历。
上图遍历为12345678。
使用队列的数据结构帮助遍历,先将根结点加入队列。
只要队列不空,就将队列的首个元素弹出。再将该元素的左右结点加入队列。这样就实现了按照层次顺序加入队列。例如:

  • 首先将1加入队列,此时队列:1;
  • 然后将1弹出,把1的左右结点2和3加入队列,此时队列:23;
  • 紧接着将2弹出,把2的左右结点4和5加入队列,此时队列:345;
  • 将3弹出,因为3没有左结点,所以加入3的右结点6,此时队列:456;
  • 将4弹出,4没有子结点,队列不加入元素:56;
  • 将5弹出,加入5的左右结点78:678;
  • 将6弹出,6也没有结点,队列:78;
  • 弹出7,7也没有子结点,队列:8;
  • 弹出8,8也没有子结点,队列:;
  • 因为此时队列为空,所以循环结束。

遍历顺序就是队列的弹出顺序12345678。

public List<Integer> levelOrder(TreeNode root) {
        List<Integer>resList=new ArrayList<>();
        if (root==null)return resList;
        LinkedList<TreeNode> q=new LinkedList<>();
        q.add(root);
        while (!q.isEmpty()){
            TreeNode cur=q.remove();
            resList.add(cur.val);
            if (cur.left!=null){
                q.add(cur.left);
            }
            if (cur.right!=null){
                q.add(cur.right);
            }
        }
        return resList;
    }

稍加修改,就可以将每一层分开,输出1,23,456,78

public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>>resList=new ArrayList<>();
        if (root==null)return resList;
        LinkedList<TreeNode> q=new LinkedList<>();
        q.add(root);
        int depth=0;
        while (!q.isEmpty()){
            resList.add(new ArrayList<>());
            int length=q.size();
            for (int i=0;i<length;i++){
                TreeNode cur=q.remove();
                resList.get(depth).add(cur.val);
                if (cur.left!=null){
                    q.add(cur.left);
                }
                if (cur.right!=null){
                    q.add(cur.right);
                }
            }
            depth++;

        }
        return resList;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值