二叉树1—二叉树的遍历

1.从上到下打印二叉树(二叉树的层序遍历)

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

/**
 * 使用层序遍历遍历二叉树打印
 * 这里需要用到队列结构(先进先出):将元素不断加入队列中,再进行出队到list中
 **/
public class Num32I_从上到下打印二叉树 {
    public int[] levelOrder(TreeNode root) {
      if(root==null){
        return new int[0];
      }
      Deque<TreeNode> queue=new ArrayDeque<>();
      ArrayList<Integer> list=new ArrayList<>();//存储队列中出来的元素
      queue.add(root);//根节点入队
      while (!queue.isEmpty()){
        TreeNode node=queue.poll();
        list.add(node.val);
        if(node.left!=null){
          queue.add(node.left);
        }
        if(node.right!=null){
          queue.add(node.right);
        }
        //保证了始终按层序顺序加入
      }
      //此时队列为空,元素遍历完毕存储在list中,向数组迁移
      int size=list.size();
      int[] array=new int[size];
      for (int i = 0; i < size; i++) {
        array[i]=list.get(i);
      }
      return array;
    }
}

从上到下打印二叉树_II

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

1.队列为空,层序遍历就处理完毕

2.队列中保存的都是下一层要处理的元素

queue.size():计算出当前层的元素个数,按这个元素个数循环,将队列中当前层元素从队列中取出并放入temp集合同时将下一层元素加入队列。

public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ret=new ArrayList<>();//定义二维数组接收形式
        if(root==null){
            return ret;
        }
        Deque<TreeNode> queue=new ArrayDeque<>();
        queue.offer(root);//根节点入队
        while (!queue.isEmpty()){
            //定义temp数组将每一层元素存入
            List<Integer> temp=new ArrayList<>();
            int size=queue.size();//当前层元素个数
            for (int i = 0; i < size; i++) {
                TreeNode cur=queue.poll();
                temp.add(cur.val);//队列中取出队首元素加入List
                if(cur.left!=null){
                    queue.offer(cur.left);
                }
                if(cur.right!=null){
                    queue.offer(cur.right);
                }
            }
            ret.add(temp);
        }
        return ret;
    }

从上到下打印二叉树_III

        请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

        与II一样,我们可以一层一层放入,但此时我们可以利用双端队列结构来维护每一层输出元素(II用的是List<Integer>=new ArrayList<>(),将元素依次加入temp),即定义一个双端队列Deque<Integer>,让元素加入双端队列,左->右时尾插加入,右->左时头插加入,保证元素输出时的之字型效果:

  • 如果从左至右,我们每次将被遍历到的元素插入至双端队列的末尾,即offerLast(),等价于offer()。

  • 如果从右至左,我们每次将被遍历到的元素插入至双端队列的头部,即offerFirst(),此时出的话就是这一层中后入的先出了(相当于栈的实现)。

  • 使用一个Boolean flag来区别是从左至右还是从右至左的情况

  public class Num32III_从上到下打印二叉树 {
    private class TreeNode {
      int val;
      TreeNode left;
      TreeNode right;
      TreeNode(int x) { val = x; }
  }
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ret=new LinkedList<>();
        if(root==null){
            return ret;
        }
        Queue<TreeNode> queue=new ArrayDeque<>();
        Boolean flag=true;
        queue.offer(root);
        while(!queue.isEmpty()){
            Deque<Integer> temp=new LinkedList<>();
            int size=queue.size();
            //当前行元素插入temp中
            for(int i=0;i<size;i++){
                TreeNode cur= queue.poll();//顺序取出的
                //判断flag,搞清楚插入方向
                if(flag){//为true是左->右加入数组
                    temp.offerLast(cur.val);
                }else {
                    temp.offerFirst(cur.val);
                }
                if(cur.left!=null){
                    queue.offer(cur.left);
                }
                if(cur.right!=null){
                    queue.offer(cur.right);
                }
            }
            ret.add(new LinkedList<>(temp));
            flag=!flag;
        }
        return ret;
    }
}

2.力扣_二叉搜索树的后序遍历序列

        输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

思路:判断数组是否是二叉搜索树,先了解特性,二叉搜索树左子树值all小于根节点值,右子树值all大于根节点值

        1)利用递归,划分左右子树,遍历数组[i,j]区间元素,找到第一个大于根节点的结点索引m,这个结点就是右子树的开始

        2)划分出左右区间,左是[i,m-1],右是[m,j-1],根节点为j【后序:左右根】

        3)判断当前划分的左右区间的元素是否左区间<根节点(已经在找大于根节点的索引时判断过了),右区间>根节点,判断遍历完毕是否索引到达根节点,到达则满足当前这一段数组满足二叉搜索树

        4)递归再划分左右区间判断左右子树是否满足二叉搜索树条件

public class Num33_二叉搜索树的后序遍历序列 {
    //后序遍历:左右根
    public boolean verifyPostorder(int[] postorder) {
        return recur(postorder,0,postorder.length-1);
    }
    /**
     * 递推工作:
     * 划分左右子树:
     * 遍历后序遍历的[i,j] 区间元素,寻找第一个大于根节点的节点,索引记为m
     * 此时,可划分出左子树区间[i,m−1]、右子树区间[m,j−1]、根节点索引j
     * 判断是否为二叉搜索树:
     * 左子树区间[i,m−1]内的所有节点都应<postorder[j]。而划分左右子树步骤已经保证左子树区间的正确性,因此只需要判断右子树区间即可。
     * 右子树区间[m,j−1]内的所有节点都应>postorder[j] 。实现方式为遍历,当遇到postorder[j]≤postorder[j] 的节点则跳出;则可通过p=j判断是否为二叉搜索树。
     */

    private boolean recur(int[] postorder,int i,int j){
        if(i>=j){
            return true;
        }
        int p=i;
        while(postorder[p]<postorder[j]){
            p++;
        }
        int m=p;//m索引对应的是第一个大于根节点的数
        //上面的遍历也保证了左子树区间节点值all小于根节点
        //继续遍历保证右子树区间都是大于根节点值的
        while(postorder[p]>postorder[j]){
            p++;
        }
        //将整个数组遍历完p若是加到了最后一个数,即p==j时,就能确定是个二叉搜索树
        //p==j:判断根节点位置对应;recur(postorder,i,m-1):判断左子树是否二叉搜索树;recur(postorder,m,j-1):判断右子树是否二叉搜索树
        return p==j&&recur(postorder,i,m-1)&&recur(postorder,m,j-1);
    }
}

3.力扣_二叉树的序列与反序列化

        请实现两个函数,分别用来序列化和反序列化二叉树。你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

public class Num37_序列与反序列化二叉树 {
    //借助层序遍历
    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {//二叉树-》字符串:借用队列(层序遍历保证顺序),二叉树元素入队,判断时用rea.append拿到二叉树数字内容
        if(root==null){
            return "[]";
        }
        StringBuilder res=new StringBuilder("[");
        Queue<TreeNode> queue=new LinkedList<>();
        queue.add(root);
        //二叉树中元素依次出队入队判断,元素不为空res+元素值,为空res+null
        while (!queue.isEmpty()){
            TreeNode cur=queue.poll();
            if(cur!=null){
                res.append(cur.val+",");
                queue.add(cur.left);
                queue.add(cur.right);
            }else{
                res.append("null,");
            }
        }
        res.deleteCharAt(res.length()-1);
        res.append("]");
        return res.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {//字符串-》二叉树
        if(data.equals("[]")){
            return null;
        }
        String[] str = data.substring(1, data.length() - 1).split(",");
        TreeNode root=new TreeNode(Integer.parseInt(str[0]));

        Queue<TreeNode> queue=new LinkedList<>();
        queue.add(root);
        int i=1;//通过i遍历,遇到null跳过.i从1开始,因为root已经处理过了
        while (!queue.isEmpty()){
            //出队当前元素判断队列内当前元素值是否为null,不是null就要创建左右节点
            TreeNode cur=queue.poll();
            if(!str[i].equals("null")){
                cur.left=new TreeNode(Integer.parseInt(str[i]));
                queue.add(cur.left);
            }
            i++;
            if(!str[i].equals("null")){
                cur.right=new TreeNode(Integer.parseInt(str[i]));
                queue.add(cur.right);
            }
            i++;
        }
        return root;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值