【数据结构的魅力】006.二叉树基本问题

二叉树基本问题

二叉树的结构

二叉树的先序,中序,后序遍历

package dataClass.code02;

import java.util.Stack;

public class RecursiveTraversalBT {

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

        public Node(int v) {
            value = v;
        }
    }

    public static void f(Node head) {
        if (head == null) {
            return;
        }
        f(head.left);
        f(head.right);
    }

    //先序打印
    public static void pre1(Node head) {
        if (head == null) {
            return;
        }
        System.out.println(head.value);
        pre1(head.left);
        pre1(head.right);
    }

    //中序打印
    public static void in1(Node head) {
        if (head == null) {
            return;
        }
        in1(head.left);
        System.out.println(head.value);
        in1(head.right);
    }

    //后序打印
    public static void pos1(Node head) {
        if (head == null) {
            return;
        }
        pos1(head.left);
        pos1(head.right);
        System.out.println(head.value);
    }

    //用栈实现的先序打印
    public static void pre2(Node head) {
        if (head != null) {
            Stack<Node> stack = new Stack<>();
            stack.add(head);
            while (!stack.isEmpty()) {
                head = stack.pop();
                if (head.right != null) {
                    stack.push(head.right);
                }
                if (head.left != null) {
                    stack.push(head.left);
                }
            }
        }
        System.out.println();
    }

    //中序遍历
    public static void in2(Node head) {
        if (head != null) {
            Stack<Node> stack = new Stack<>();
            while (!stack.isEmpty() || head != null) {
                if (head != null) {
                    stack.push(head);
                    head = head.left;
                } else {
                    head = stack.pop();
                    System.out.println(head.value);
                    head = head.right;
                }
            }
        }
        System.out.println();
    }

    //基于特殊先序的后序遍历
    public static void pos2(Node head) {
        if (head != null) {
            Stack<Node> s1 = new Stack<>();
            Stack<Node> s2 = new Stack<>();
            s1.push(head);
            while (!s1.isEmpty()) {
                head = s1.pop();
                s2.push(head);
                if (head.left != null) {
                    s1.push(head.left);
                }
                if (head.right != null) {
                    s1.push(head.right);
                }
            }
            while (!s2.isEmpty()) {
                System.out.println(s2.pop());
            }
        }
    }

    //只使用一个栈来进行后序遍历
    public static void pos3(Node h) {
        if (h != null) {
            Stack<Node> stack = new Stack<>();
            stack.push(h);
            Node c = null;
            while (!stack.isEmpty()) {
                c = stack.peek();
                if (c.left != null && h != c.left && h != c.right) {
                    stack.push(c.left);
                } else if (c.right != null && h != c.right) {
                    stack.push(c.right);
                } else {
                    System.out.println(stack.pop());
                    h = c;
                }
            }
        }
    }
}

二叉树的按层遍历

1)宽度遍历

2)发现某一层的结束(最大宽度)

public static int maxWidthUseMap(Node head){
        if(head==null){
            return 0;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(head);
        HashMap<Node,Integer> levelMap = new HashMap<>();
        levelMap.put(head,1);
        int curLevel = 1;//当前正在统计那一层
        int curLevelNodes = 0;//当前正在统计那一层的宽度
        int max = 0;//所有层中的最大值
        while (!queue.isEmpty()){
            Node cur = queue.poll();
            int curNodeLevel = levelMap.get(cur);
            if(cur.left!=null){
                levelMap.put(cur.left,curNodeLevel+1);
                queue.add(cur.left);
            }
            if(cur.right!=null){
                levelMap.put(cur.right,curNodeLevel+1);
                queue.add(cur.right);
            }
            if(curNodeLevel==curLevel){
                curLevelNodes++;
            }else {
                max = Math.max(max,curLevelNodes);
                curLevel++;
                curLevelNodes = 1;
            }
        }
        max = Math.max(max,curLevelNodes);
        return max;
    }

返回后继节点

public static Node getSuccessorNdoe(Node node) {
        if (node == null) {
            return node;
        }
        if (node.right != null) {
            return getLeftMost(node.right);
        } else {//无右树
            Node parent = node.parent;
            while (parent != null && parent.right == node) {
                //当前节点是其父亲节点的右孩子
                node = parent;
                parent = node.parent;
            }
            return parent;
        }
    }

    /**
     * 找到右树上的最左节点
     *
     * @param node 当前节点
     */
    public static Node getLeftMost(Node node) {
        if (node == null) {
            return node;
        }
        while (node.left != null) {
            node = node.left;
        }
        return node;
    }

折纸问题

public static void printAllFold(int N) {
        printProcess(1, N, true);
    }

    /**
     * 递归过程,来到了某一个节点
     * @param i 节点的层数
     * @param N 一共有多少层(固定)
     * @param down ==true:凹     ==false:凸
     */
    private static void printProcess(int i, int N, boolean down) {
        if (i > N) {
            return;
        }
        printProcess(i + 1, N, true);
        System.out.println(down ? "凹" : "凸");
        printProcess(i + 1, N, false);
    }

    public static void main(String[] args) {
        int N = 3;
        printAllFold(N);
    }

二叉树递归套路

1)判断平衡二叉树

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

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

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

    public static class Info {
        public boolean isBalaced;
        public int height;

        public Info(boolean b, int h) {
            isBalaced = b;
            height = h;
        }
    }

    public static Info process(Node x) {
        if (x == null) {
            return new Info(true, 0);
        }
        Info leftInfo = process(x.left);
        Info rightInfo = process(x.right);
        //左树或者右树的高度加根节点的高度就是当前树高
        int height = Math.max(leftInfo.height, rightInfo.height) + 1;
        boolean isBalaced = true;
        if (!leftInfo.isBalaced || !rightInfo.isBalaced || Math.abs(leftInfo.height - rightInfo.height) > 1) {
            isBalaced = false;
        }
        return new Info(isBalaced, height);
    }

2)最大距离

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

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

    public static int maxDistance(Node head){
        return process(head).maxDistance;
    }

    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){
        if(x==null){
            return new Info(0,0);
        }
        Info leftInfo = process(x.left);
        Info rightInfo = process(x.right);
        int height = Math.max(leftInfo.height, rightInfo.height)+1;
        int maxDistance = Math.max(Math.max(leftInfo.maxDistance, rightInfo.maxDistance), leftInfo.height+ rightInfo.height+1);
        return new Info(maxDistance,height);
    }

3)派对的最大快乐值

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

        public Employee(int h){
            happy = h;
            nexts = new ArrayList<>();
        }
    }

    public static class Info{
        //头结点在来的时候整棵树的最大值
        public int yes;
        //头结点在不来的时候整棵树的最大值
        public int no;

        public Info(int y,int n){
            yes = y;
            no = n;
        }
    }

    public static Info process(Employee x){
        if(x.nexts.isEmpty()){
            return new Info(x.happy, 0);
        }
        int yes = x.happy;
        int no = 0;
        for(Employee next : x.nexts){
            Info nextInfo = process(next);
            yes += nextInfo.no;
            no += Math.max(nextInfo.yes, nextInfo.no);
        }
        return new Info(yes, no);
    }

4)是否是满二叉树

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

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

    public static boolean isFull(Node head){
        if(head == null){
            return true;
        }
        Info all = process(head);
        return (1 << all.height)-1 == all.nodes;
    }

    public static class Info{
        public int height;
        public int nodes;

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

    public static Info process(Node head){
        if(head == null){
            return new Info(0,0);
        }
        Info leftInfo = process(head.left);
        Info rightInfo = process(head.right);
        int height = Math.max(leftInfo.height, rightInfo.height)+1;
        int nodes = leftInfo.nodes+rightInfo.nodes+1;
        return new Info(height,nodes);
    }
}

5)判断是否为完全二叉树

思路:

  1. 任何节点有右孩子而没有左孩子,直接返回false,否则继续
  2. 一但遇到左右孩子不双全,后续所遇到的节点必须全部为叶节点
public class IsCBT {
    public static class Node {
        public int value;
        public IsCBT.Node left;
        public IsCBT.Node right;

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

    public static boolean isBCT1(Node head) {
        if (head == null) {
            return true;
        }
        //宽度优先遍历使用队列
        LinkedList<Node> queue = new LinkedList<>();
        //是否遇到过左右孩子不双全的节点
        boolean leaf = false;
        Node l = null;
        Node r = null;
        queue.add(head);
        while (!queue.isEmpty()) {
            head = queue.poll();
            l = head.left;
            r = head.right;
            //如果遇到了不不双全的节点,又发现当前节点不是叶节点
            if ((leaf && !(l == null && r == null)) || (l == null && r != null)) {
                return false;
            }
            if (l != null) {
                queue.add(l);
            }
            if (r != null) {
                queue.add(r);
            }
            if (l == null || r == null) {
                leaf = true;
            }
        }
        return true;
    }

    /*
        递归套路
        1)左边是满二叉树,右边是满二叉树,左右高度一样
        2)左边是满二叉树,右边是满二叉树,左比右高一
        3)左边是完全二叉树,右边是满二叉树,左比右高一
        4)左边是满二叉树,右边是完全二叉树,左右高度相等

    */

    public static boolean isCBT2(Node head) {
        if (head == null) {
            return true;
        }
        return process(head).isCBT;
    }

    //对于每一颗子树,是否是满二叉树,是否是完全二叉树,高度
    public static class Info {
        public boolean isFull;
        public boolean isCBT;
        public int height;

        public Info(boolean full, boolean cbt, int h) {
            isFull = full;
            isCBT = cbt;
            height = h;
        }
    }

    public static Info process(Node x) {
        if (x == null) {
            return new Info(true, true, 0);
        }
        Info leftInfo = process(x.left);
        Info rightInfo = process(x.right);

        int height = Math.max(leftInfo.height, rightInfo.height) + 1;
        boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
        boolean isCBT = false;
        if (isFull) {
            isCBT = true;
        } else {
            if (leftInfo.isCBT && leftInfo.isCBT) {
                if (leftInfo.isCBT && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
                    isCBT = true;
                }
                if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
                    isCBT = true;
                }
                if (leftInfo.isFull && rightInfo.isCBT && leftInfo.height == rightInfo.height) {
                    isCBT = true;
                }
            }
        }
        return new Info(isFull, isCBT, height);
    }
}

6)最低公共祖先问题

package dataClass.code02;

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

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

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

    public static Node lowestAncestor1(Node head,Node o1,Node o2){
        if(head == null){
            return null;
        }
        //key的父节点是value
        HashMap<Node,Node> parentMap = new HashMap<>();
        parentMap.put(head, null);
        fillParentMap(head,parentMap);
        HashSet<Node> o1Set = new HashSet<>();
        Node cur = o1;
        o1Set.add(cur);
        while (parentMap.get(cur)!=null){
            cur = parentMap.get(cur);
            o1Set.add(cur);
        }
        cur = o2;
        while (!o1Set.contains(cur)){
            cur = parentMap.get(cur);
        }
        return cur;
    }

    public static void fillParentMap(Node head,HashMap<Node,Node> parentMap){
        if(head.left!=null){
            parentMap.put(head.left,head);
            //递归填写左树的所有节点
            fillParentMap(head.left,parentMap);
        }
        if(head.right!=null){
            parentMap.put(head.right,head);
            //递归填写右树的所有节点
            fillParentMap(head.right,parentMap);
        }
    }


    /*
        递归套路
        1) o1,o2没有一个在x上
        2) o1,o2只有一个在x上
        3) o1,o2都在x为头结点的树上
            1.左右各有一个
            2.左子树包含所有的o1,o2
            3.右子树包含所有的o1,o2
            4.o1,o2有一个在头结点上,另一个在子树中
     */

    //任何子树返回三个信息,最初的交汇点,是否发现o1,是否发现o2
    public static class Info{
        public Node ans;
        public boolean findO1;
        public boolean findO2;

        public Info(Node a,boolean f1,boolean f2){
            ans = a;
            findO1 = f1;
            findO2 = f2;
        }
    }

    public static Info process(Node x,Node o1,Node o2){
        if(x == null){
            return new Info(null,false,false);
        }
        Info leftInfo = process(x.left,o1,o2);
        Info rightInfo = process(x.right,o1,o2);

        boolean findO1 = x == o1 || leftInfo.findO1 || rightInfo.findO1;
        boolean findO2 = x == o2 || leftInfo.findO2 || rightInfo.findO2;

        //o1和o2最初的交汇点
        Node ans = null;
        if(leftInfo.ans!=null){
            ans = leftInfo.ans;
        }
        if(rightInfo.ans!=null){
            ans = rightInfo.ans;
        }
        if(ans == null){
            if(findO1 && findO2){
                ans = x;
            }
        }
        return new Info(ans,findO1,findO2);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值