只用一文整理好构建二叉树的算法大总结:序列化和反序列化+给出中序(前序/后序)构建+有序数组构建平衡搜索二叉树

这篇博客详细介绍了如何对二叉树进行序列化和反序列化操作,包括前序、中序、后序和层序四种遍历方法。针对每种遍历方式,提供了相应的序列化和反序列化实现,并重点讲解了如何利用这些遍历序列来构建二叉树。此外,还讨论了有序数组构建二叉搜索树的递归策略。
摘要由CSDN通过智能技术生成

序列化二叉树

三大遍历+层序遍历序列化

结构

public static class Node{
        int value;
        Node left;
        Node right;
        public Node(int value){
            this.value=value;
        }
    }

四大遍历序列化

public static void preSerializable(Node root,Queue<Integer> queue){
        if(root==null) queue.add(null);
        else{
            queue.add(root.value);
            preSerializable(root.left,queue);
            preSerializable(root.right,queue);
        }
    }
    public static  void inSerializable(Node root,Queue<Integer> queue){
        if(root==null) queue.add(null);
        else{
            inSerializable(root.left,queue);
            queue.add(root.value);
            inSerializable(root.right,queue);
        }
    }
    public static void posSerializable(Node root,Queue<Integer> queue){
        if(root==null) queue.add(null);
        else{
            posSerializable(root.left,queue);
            posSerializable(root.right,queue);
            queue.add(root.value);
        }
    }

层序遍历
public static void levelSerial(Node head){
      Queue<String> data=new LinkedList<>();
      if(head==null) {
          data.add(null);
          return;
      } else {
          //遍历依赖的队列
          Queue<Node> queue = new LinkedList<>();
          queue.add(head);
          data.offer(String.valueOf(head.value));
          while (!queue.isEmpty()) {
              head = queue.poll();
              if (head.left != null) {
                  queue.offer(head.left);
                  data.offer(String.valueOf(head.left));
              } else {
                  data.offer(null);
              }


              if (head.right != null) {
                  queue.offer(head.right);
                  data.offer(String.valueOf(head.right));
              } else {
                  data.offer(null);
              }
          }
      }
    }

反序列二叉树(构建)

关键:先的抓到本结点,然后去构建子树和右树

先序遍历序列化后的构建
 public static Node unPreSerial(Queue<String> queue){
        String value = queue.poll();
        if(value==null)  return null;
        Node head=new Node(Integer.valueOf(value));
        head.left= unPreSerial(queue);
        head.right=unPreSerial(queue);
        return head;
    }

后序遍历序列化后的构建    
后序遍历时候,中间结点是最后面的,当时我们需要最先抓到中间结点
方法:左右中===>中右左
public static void unPosSerial(Queue<String> queue){
        String value = queue.poll();
        if(value==null) return;
        Stack<String> stack=new Stack<>();
        stack.push(value);
        while(!queue.isEmpty()){
            stack.push(queue.poll());//左右中---中右左
        }
    }
拿到中右左的序列就好先构建中间结点了    
    public static Node unPosSerial(Stack<String> stack){
        String value=stack.pop();
        if(value==null) return  null;
        else{
            Node head=new Node(Integer.valueOf(value));
            head.left=unPosSerial(stack);
            head.right=unPosSerial(stack);
            return head;
        }
    }

层序遍历序列化的构建

 public static Node GenerateNode(String value){
        if(value==null) return null;
        else{
            return new Node(Integer.valueOf(value));
        }
    }
 public static Node unLevel(Queue<String> data){
        String value = data.poll();
        if(value==null){
            return null;
        }else{
            Queue<Node> queue=new LinkedList<>();
            Node head = Generate(value);
            queue.add(head);
            while(!queue.isEmpty()){
                Node cur = queue.poll();//如果一层弹完了,data里的对应层的下一层的结点也是会弹完的(queue弹一层,data要弹出它的孩子)
                cur.left=Generate(data.poll());
                cur.right=Generate(data.poll());
                if(cur.left!=null) queue.add(cur.left);
                if(cur.right!=null) queue.add(cur.right);
            }
        return head;
        }
    }  

再次强调:构建二叉树,首先要抓到本节点的node(先new中间的结点,再后面去构建它的左右子树)

强加练习:给出中序和后序/前序遍历的数组,构建二叉树

中序加后序:

思想:后序数组最后一个元素确定了中间结点的值root,在中序数组中找到该值,以此分割中序左数组和右边数组,左数组对应左子树,右数组对应右子树,
划分后序数组的左右子数组:
根据中序的左子数组的长度是等于后序数组的左子数组的长度,划分好后序左子数组后,后面的元素,除了最后一个元素,都是后序的右子数组
中序左子数组和后序左子数组=====>去构建左子树(root.left)
右子数组一样
发现:这个过程是一个递归过程

代码

class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        //构造结点,构造左子树,构造右子树
        return process(inorder,0,inorder.length-1,postorder,0,postorder.length-1);
    }
public TreeNode process(int[] inorder,int inleft,int inright,int[] postorder,int posleft,int posright){
    if(inright<inleft) return null;
    if(inright==inleft) return new TreeNode(inorder[inleft]);

    //正常情况
    //1:得到根结点:对于数组元素的取值,需要用左右遍历
    TreeNode root=new TreeNode(postorder[posright]);
    int rootIndex=0;
    for(int i=inleft;i<=inright;i++){
        if(inorder[i]==root.val){
            rootIndex=i;//找到根节点在中序数组中的位置
            break;
        }
    }
    //构建左子树(前闭后开),左参数是index,右参数是长度
    root.left=process(inorder,inleft,rootIndex-1,postorder,posleft,posleft+(rootIndex-inleft-1));
    root.right=process(inorder,rootIndex+1,inright,postorder,posleft+(rootIndex-inleft),posright-1);
    return root;
}

}
中序和前序

思想:和前面一样
代码

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return process(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
    }
public TreeNode process(int[] preorder,int preLeft,int preRight,int[] inorder,int inLeft,int inRight){
        //basecase
        if(inLeft>inRight) return null;
        if(inLeft==inRight) return new TreeNode(inorder[inLeft]);
        //正常情况
        TreeNode root=new TreeNode(preorder[preLeft]);
        int rootIndex=0;
        for(int i=inLeft;i<=inRight;i++){
            if(root.val==inorder[i]){
                rootIndex=i;
                break;
            }
        }
        //构建子树
        root.left=process(preorder,preLeft+1,preLeft+(rootIndex-inLeft),inorder,inLeft,rootIndex-1);
        root.right=process(preorder,preLeft+(rootIndex-inLeft)+1,preRight,inorder,rootIndex+1,inRight);
        return root;
}
}
有序数组构建BST(二查搜索树)

递归思想:
每次取中间的元素作为root,分割数组左右子数组,分别作为左右子树
代码

class Solution {
	public TreeNode sortedArrayToBST(int[] nums) {
        return build(nums,0,nums.length-1);
	}

	public TreeNode build(int[] nums ,int L,int R){
        //每次取中间,取到的作为root,左子树用左数组,右子树用右数组
        if(L>R) return null;
        int mid=L+((R-L)>>1);
        TreeNode root=new TreeNode(nums[mid]);
        root.left=build(nums,L,mid-1);
        root.right=build(nums,mid+1,R);
        return root;
    }
}

总结:

1:每次都是先抓到本结点,才可以处理它的左右子树
2:如果是递归思想:每次处理好了本结点,处理它的左右孩子的时候,直接递归

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赑屃爱Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值