二叉树相关(是否为搜索二叉树、完全二叉树、平衡二叉树、满二叉树等等)

本文详细介绍了如何判断二叉树是否为搜索二叉树、完全二叉树、平衡二叉树以及满二叉树,并提供了相应的Java代码实现。此外,还讲解了寻找二叉树节点的最低公共祖先以及后继节点的方法,以及二叉树的序列化和反序列化操作。内容涵盖了二叉树的基础算法及其应用。
摘要由CSDN通过智能技术生成

1、判断二叉树是否是搜索二叉树(左>根>右)

方法一:设置一个值记录前一个数,和当前数做比较,(中序遍历)若一直递增则为搜索二叉树,一旦发现当前数没有大于后者,违反了搜索二叉树定义

package learn;

public class Test {

        public static class Node{
            public int value;
            public Node left;
            public Node right;
            public Node(int value){//构造方法

                this.value=value;
            }
        }

        public static int preValue=Integer.MIN_VALUE;//记录中序遍历当前节点的前一个节点值
        public static boolean checkBST(Node head) {//左根右
            if (head == null) {
                return true;
            }
            
            if(checkBST(head.left)==false){//左子树不是二叉搜索树,则此树不可能是二叉搜索树
                return false;
            }
            
            if(head.value<=preValue){
                return false;
            }else {
                preValue= head.value;
            }
            
            return checkBST(head.right);
        }
}

方法二:中序遍历,将二叉树的值依次放入一个链表存储,然后打印观察

        public static void checkBST2(Node head) {//左根右
            List<Node> l = new ArrayList<>();
            process(head, l);
            for(int i=0;i<l.size();i++){
                System.out.print(l.get(i)+" ");
            }
        }

        public static void process(Node head,List<Node> l) {
            if(head==null)return;
            process(head.left,l);
            l.add(head.value);
            process(head.right,l);
        }

方法三:按二叉树题目的套路解题,分为左子树、右子树,返回值类型为需要左子树提供的值和需要右子树提供的值的汇总

package learn;

public class Test {

        public static class Node{
            public int value;
            public Node left;
            public Node right;
            public Node(int value){//构造方法

                this.value=value;
            }
        }

        public static class returnType{//定义递归返回值类型
            public boolean isBST;//是否为搜索二叉树
            public int min;//当前子树的最小值
            public int max;

            public returnType(boolean is,int min,int max){
                isBST=is;
                this.min=min;
                this.max=max;
            }
        }

        public static boolean isBST(Node head) {
            return process(head).isBST;
        }

        public static returnType process(Node head) {
            if(head==null){
                return null;
            }
            
            int min=head.value;
            int max=head.value;
            
            returnType left=process(head.left);
            returnType right=process(head.right);

            if(left!=null){
                min=Math.min(min,left.min);
                max=Math.max(max,left.max);
            }

            if(right!=null){
                min=Math.min(min,right.min);
                max=Math.max(max,right.max);
            }
            //当前树的min为其左子树最小值和根和右子树最小值 中的最小值
            
            boolean isBST=true;
            if(left!=null && (!left.isBST || left.max>=head.value)){//左子树不是二叉搜索树 或 左子树最大值不小于根
                isBST=false;
            }

            if(right!=null && (!right.isBST || right.min<=head.value)){//右子树不是二叉搜索树 或 右子树最小值不大于根
                isBST=false;
            }
            return new returnType(isBST,min,max);
        }
}

2、判断是否为完全二叉树
节点不能有右无左,宽度优先遍历过程若遇到一个节点孩子不双全,从此节点后都应为叶子节点

        public static boolean checkCBT(Node head) {
            if(head==null){
                return true;
            }
            boolean flag=false;//还未遇到孩子不双全的节点
            Queue<Node> q=new LinkedList<>();
            q.add(head);
            Node l=null;
            Node r=null;
            while (!q.isEmpty()){
                head=q.poll();
                l=head.left;
                r=head.right;

                if(r!=null && l==null){//有右无左
                    return false;
                }
                if(flag && (l!=null || r!=null)){//已经遇到孩子不双全节点后,还遇到不为叶子的节点
                    return false;
                }

                if(l!=null){
                    q.add(l);
                }
                if (r!=null){
                    q.add(r);
                }
                if(l==null || r==null){
                    flag=true;
                }
            }
            return true;
        }

3、判断是否为平衡二叉树

package learn;

public class Test {

        public static class Node{
            public int value;
            public Node left;
            public Node right;
            public Node(int value){//构造方法

                this.value=value;
            }
        }
        
        public static class returnType{//定义递归返回值类型
            public boolean isBalanced;//是否为平衡二叉树
            public int height;//树高度
            
            public returnType(boolean is,int h){
                isBalanced=is;
                height=h;
            }
        }

        public static boolean isBalanced(Node head) {
            return process(head).isBalanced;
        }

        public static returnType process(Node head) {
            if(head==null){
                return new returnType(true,0);
            }

            returnType left=process(head.left);
            returnType right=process(head.right);

            int height=Math.max(left.height, right.height)+1;
            boolean isBalanced=left.isBalanced && right.isBalanced && (Math.abs(left.height- right.height)<2);
            return new returnType(isBalanced,height);
        }
}

4、判断是否为满二叉树
最后需要整棵树的节点值和深度,满足N=2^h-1,即为满二叉树

public class Test {

        public static class Node{
            public int value;
            public Node left;
            public Node right;
            public Node(int value){//构造方法

                this.value=value;
            }
        }

        public static class returnType{//定义递归返回值类型
            public int height;
            public int nodes;

            public returnType(int h,int n){
                height=h;
                nodes=n;
            }
        }

        public static boolean isFull(Node head) {
            returnType rt=process(head);
            int h=rt.height;
            int n=rt.nodes;
            return n==Math.pow(2,h)-1;
        }

        public static returnType process(Node head) {
            if(head==null){
                return new returnType(0,0);
            }

            returnType left=process(head.left);
            returnType right=process(head.right);
            int height=Math.max(left.height, right.height)+1;
            int nodes=left.nodes+right.nodes+1;
            return new returnType(height,nodes);
        }
}

5、给两个二叉树的节点o1,o2,找它们的最低公共祖先节点

(1)方法一:用一个HashMap来记录每个节点的双亲,然后o1往上走,在s中记录o1的各个祖先和自身(自身也可能为公共祖先),o2往上走,看o2自身和各祖先是否在s中

package learn;

import java.util.HashMap;
import java.util.HashSet;

public class Test {

        public static class Node{
            public int value;
            public Node left;
            public Node right;
            
            public Node(int value){//构造方法

                this.value=value;
            }
        }


        public static Node lca(Node head,Node o1,Node o2) {
            HashMap<Node,Node> h=new HashMap<>();
            h.put(head,head);//设定head的祖先为它自己
            process(head,h);
            
            Node cur=o1;
            HashSet<Node> s=new HashSet<>();
            while (cur!=h.get(cur)){//往上走,直到根 根未放入s 根不放也没事 根是必然的公共祖先,若无其余非根祖先,则返回根
                s.add(cur);
                cur=h.get(cur);
            }
            s.add(head);
            
            Node cur2=o2;
            while (cur2!=h.get(cur2)){//o2往上走,看o2是否在s中
                if(s.contains(cur2)){
                    return cur2;
                }
                cur2=h.get(cur2);
            }
            return head;
        }
        
//此处利用先序遍历添加元素和其父节点的联系(任意二叉树遍历方式都可)
        public static void process(Node head,HashMap<Node,Node> h) {
            if(head==null){
                return ;
            }
            if(head.left!=null){
            	h.put(head.left,head);
            }
            if(head.right!=null){
            	h.put(head.right, head);
            }
            process(head.left,h);
            process(head.right,h);
        }
}

(2)方法二:

        public static Node lca(Node head,Node o1,Node o2) {
            if(head==null || head==o1 || head==o2){
                return head;
            }
            
            Node left=lca(head.left,o1,o2);
            Node right=lca(head.right,o1,o2);
            
            if(left!=null && right!=null){//说明左右各有o1、o2
                return head;
            }
            
            return left!=null ? left: right;//返回有给定节点的
        }

6、在二叉树中找到一个节点的后继节点(中序遍历)
该二叉树节点结构有指向其父亲的指针

package learn;

public class Test {

        public static class Node{
            public int value;
            public Node left;
            public Node right;
            public Node parent;
            public Node(int value){//构造方法

                this.value=value;
            }
        }


        public static Node getNextNode(Node node) {
            if(node==null){
                return node;
            }

            if(node.right!=null){//有右子树 找node右孩子的最左
                return getLeftMost(node.right);
            }else {//无右子树
                Node parent=node.parent;
                while (parent!=null && node!=parent.left){
                    node=parent;
                    parent=node.parent;
                }
                return parent;
            }
        }

        public static Node getLeftMost(Node node) {
            if(node==null){
                return node;
            }
            while (node.left!=null){
                node=node.left;
            }
            return node;
        }
}

7、二叉树的序列化和反序列化
若按先序:
(1)序列化:

        public static String serialByPre(Node node) {//按先序 序列化
            if(node==null){
                return "#_"; 
            }

            String res=node.value+"_";//根
            res+=serialByPre(node.left);//左
            res+=serialByPre(node.right);//右
            
            return res;
        }

(2)反序列化:

package learn;

import java.util.LinkedList;
import java.util.Queue;

public class Test {

        public static class Node{
            public int value;
            public Node left;
            public Node right;
            public Node(int value){//构造方法

                this.value=value;
            }
        }

        public static Node deserializeByPre(String s) {//按先序 序列化
            String[] x=s.split("_");//x存储各节点信息

            Queue<String> q=new LinkedList<>();
            for(int i=0;i< x.length;i++){
                q.add(x[i]);
            }
            //设置队列在于 每建好一个节点 此节点已经出队 找到下个节点很方便
            return process(q);
        }

        public static Node process(Queue<String> q) {
            String s=q.poll();
            if(s.equals("#")) {//判断字符串是否相等 用equals
                return null;
            }
            Node head=new Node(Integer.valueOf(s));//建根
            head.left=process(q);//建左子树
            head.right=process(q);//建右子树
            
            return head;
        }
}

8、题目:将纸条折叠N次,输出纸条打开后,从左至右,折痕的凹凸情况

        public static void printALLFolds(int N) {//N:总需折叠次数
            printProcess(1,N,true);
        }

        public static void printProcess(int i,int n,boolean x) {//i:当前折叠次数 x:标记为“凹”还是“凸”
            if(i>n){
                return;
            }
            
            printProcess(i+1,n,true);
            System.out.println(x?"凹":"凸");
            printProcess(i+1,n,false);
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值