二叉树递归套路题和morris遍历

二叉树相关题:
1、二叉树递归套路:分左右子树收集信息,最后做消息整合,分别向左子树和右子树要信息

(1)二叉树节点的最大距离问题:节点a到b的距离为a到b路径上的节点个数

package day;

public class Demo {
    public static class Node{
        public int value;
        public Node left;
        public Node right;

        public Node(int data){
            this.value=data;
        }
    }

    public static class Info{//返回值类型
        public int maxDistance;
        public int height;

        public Info(int dis,int h){
            maxDistance=dis;
            height=h;
        }
    }

    public static Info process(Node x){
        //以x为头的树,最大距离分为经过x:两边树高相加再加1;不经过x:最大距离为左或右数最大距离
        if(x==null){
            return new Info(0,0);
        }
        Info left=process(x.left);
        Info right=process(x.right);
        int leftDis=left.maxDistance;
        int rightDis=right.maxDistance;
        int xDis=1+left.height+right.height;

        int max=Math.max(xDis,Math.max(leftDis,rightDis));

        return new Info(max,Math.max(left.height,right.height)+1);
    }
    
    public static int maxDistance(Node head){
        return process(head).maxDistance;
    }
}

(2)派对最大快乐值:
在这里插入图片描述

package day;

import java.util.*;

public class Demo {
    public static class Employee{
        public int happy;
        public List<Employee> nexts;
    }

    public static class Info{//返回值类型
        public int laiMaxHappy;
        public int buMaxHappy;

        public Info(int lai,int bu){
            laiMaxHappy=lai;
            buMaxHappy=bu;
        }
    }

    public static Info process(Employee x){
        if(x.nexts.isEmpty()){//基层员工
            return new Info(x.happy,0);
        }
        
        int lai=x.happy;
        int bu=0;
        
        for(Employee e:x.nexts){//e为x的下层员工
            Info i=process(e);
            lai+=i.buMaxHappy;
            bu+=i.laiMaxHappy;
        }
        
        return new Info(lai,bu);
    }

    public static int maxHappy(Employee boss){
        Info headInfo=process(boss);
        return Math.max(headInfo.laiMaxHappy,headInfo.buMaxHappy);
    }
}

2、Morris遍历:(记忆)

package day;

public class Demo {
    public static class Node{
        public int value;
        public Node left;
        public Node right;

        public Node(int data){
            this.value=data;
        }
    }
    
    public static void morris(Node head){
        if(head==null){
            return;
        }
        
        Node cur=head;//cur为当前节点
        Node mostRight=null;//记录cur左子树最右节点
        
        while (cur!=null){
            mostRight=cur.left;
            if(mostRight!=null){//cur有左子树(左孩子)
                while(mostRight.right!=null && mostRight.right!=cur){
                    mostRight=mostRight.right;
                }//循环结束,mostRight指向cur左子树最右节点
                
                if(mostRight.right==null){//第一次来到cur节点
                    mostRight.right=cur;
                    cur=cur.left;
                    continue;//结束本次循环
                }else {//mostRight.right==cur,第二次来到cur节点
                    mostRight.right=null;
                }
            }
            cur=cur.right;
        }
    }
}

先序:第一次到cur时打印

package day;

public class Demo {
    public static class Node{
        public int value;
        public Node left;
        public Node right;

        public Node(int data){
            this.value=data;
        }
    }

    public static void morris(Node head){
        if(head==null){
            return;
        }

        Node cur=head;//cur为当前节点
        Node mostRight=null;//记录cur左子树最右节点

        while (cur!=null){
            mostRight=cur.left;
            if(mostRight!=null){//cur有左子树(左孩子)
                while(mostRight.right!=null && mostRight.right!=cur){
                    mostRight=mostRight.right;
                }//循环结束,mostRight指向cur左子树最右节点

                if(mostRight.right==null){//第一次来到cur节点
                    System.out.println(cur.value);
                    mostRight.right=cur;
                    cur=cur.left;
                    continue;//结束本次循环
                }else {//mostRight.right==cur,第二次来到cur节点
                    mostRight.right=null;
                }
            }else {//cur没有左孩子,只会经过一次cur
                System.out.println(cur.value);
            }
            cur=cur.right;
        }
    }
}

中序:第二次到cur时打印

package day;

public class Demo {
    public static class Node{
        public int value;
        public Node left;
        public Node right;

        public Node(int data){
            this.value=data;
        }
    }

    public static void morris(Node head){
        if(head==null){
            return;
        }

        Node cur=head;//cur为当前节点
        Node mostRight=null;//记录cur左子树最右节点

        while (cur!=null){
            mostRight=cur.left;
            if(mostRight!=null){//cur有左子树(左孩子)
                while(mostRight.right!=null && mostRight.right!=cur){
                    mostRight=mostRight.right;
                }//循环结束,mostRight指向cur左子树最右节点

                if(mostRight.right==null){//第一次来到cur节点
                    mostRight.right=cur;
                    cur=cur.left;
                    continue;//结束本次循环
                }else {//mostRight.right==cur,第二次来到cur节点
                    mostRight.right=null;
                }
            }
            System.out.println(cur.value);
            cur=cur.right;
        }
    }
}

后序:比先序和中序麻烦些,有点技巧(记忆)

public class Demo {
    public static class Node{
        public int value;
        public Node left;
        public Node right;

        public Node(int data){
            this.value=data;
        }
    }

    public static void morris(Node head){
        if(head==null){
            return;
        }

        Node cur=head;//cur为当前节点
        Node mostRight=null;//记录cur左子树最右节点

        while (cur!=null){
            mostRight=cur.left;
            if(mostRight!=null){//cur有左子树(左孩子)
                while(mostRight.right!=null && mostRight.right!=cur){
                    mostRight=mostRight.right;
                }//循环结束,mostRight指向cur左子树最右节点

                if(mostRight.right==null){//第一次来到cur节点
                    mostRight.right=cur;
                    cur=cur.left;
                    continue;//结束本次循环
                }else {//mostRight.right==cur,第二次来到cur节点
                    mostRight.right=null;
                    printEdge(cur.left);//逆序打印cur左孩子右边界
                }
            }
            cur=cur.right;
        }
        
        printEdge(head);//最后单独逆序打印整棵树右边界,即根的右边界
    }

    public static void printEdge(Node x) {
        Node tail=reverse(x);//反转链表,此时tail指向右边界最后一个节点
        Node cur=tail;
        while (cur!=null){
            System.out.println(cur.value);
            cur=cur.right;
        }
        reverse(tail);//反转回去
    }

    public static Node reverse(Node x) {
        //x为当前节点
        Node pre=null;//前一个节点
        Node next=null;//后一个节点

        while (x!=null){
            next=x.right;
            x.right=pre;
            pre=x;
            x=next;
        }
        return pre;
    }

}

morris可以用于判断是否为搜索二叉树:(中序遍历)

public class Demo {
    public static class Node{
        public int value;
        public Node left;
        public Node right;

        public Node(int data){
            this.value=data;
        }
    }

    public static boolean isBST(Node head){
        if(head==null){
            return true;
        }

        Node cur=head;//cur为当前节点
        Node mostRight=null;//记录cur左子树最右节点
        int preValue=Integer.MIN_VALUE;

        while (cur!=null){
            mostRight=cur.left;
            if(mostRight!=null){//cur有左子树(左孩子)
                while(mostRight.right!=null && mostRight.right!=cur){
                    mostRight=mostRight.right;
                }//循环结束,mostRight指向cur左子树最右节点

                if(mostRight.right==null){//第一次来到cur节点
                    mostRight.right=cur;
                    cur=cur.left;
                    continue;//结束本次循环
                }else {//mostRight.right==cur,第二次来到cur节点
                    mostRight.right=null;
                }
            }
            if(cur.value<=preValue){
                return false;
            }
            cur=cur.right;
        }
        return true;
    }



}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值