二叉树进阶问题

1.判断一颗树是否是完全二叉树

1.判断一棵树是否是完全二叉树:
(1)完全二叉树该树中若存在右子树则必然存在左子树
(2)完全二叉树的节点编号必须和满二叉树一一对应(你有的节点必须和满二叉树节点编号相同)。
(3)对于完全二叉树来说一共存在三种节点:
A.度为2的节点有N个
B.度为1的节点最多有一个(恰好就是左树的那个一个节点)
C.度为0的节点有N个
(4)判断方法:
在这里插入图片描述

package bin_tree.leetcode;

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

public class IsCompleteTree {
    public boolean isCompleteTree(TreeNode root) {
        if (root == null) {
            return true;
        }
        // 层序遍历判断二叉树
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        // 引入标志位,来区分当前遍历过程处在第一还是第二阶段
        boolean isSecondStep = false;
        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            if (!isSecondStep) {
                // 此时处在第一阶段
                if (cur.left != null && cur.right != null) {
                    // 当前cur左右子树全部都存在
                    queue.offer(cur.left);
                    queue.offer(cur.right);
                }else if (cur.left == null && cur.right != null) {
                    // 此时只有右树没有左树,反例
                    return false;
                }else if (cur.left != null) {
                    // 只有左树没有右树,此时cur是碰到的第一个只有左树的节点
                    // 切换状态
                    isSecondStep = true;
                    queue.offer(cur.left);
                }else {
                    // 此时左树和右树全部为空,cur第一个碰到的叶子节点
                    isSecondStep = true;
                }
            }else {
                // 此时处在第二阶段,第二阶段中的所有节点不可能有子树
                // 有一个反例就false
                if (cur.left != null || cur.right != null) {
                    return false;
                }
            }
        }
        // 遍历全部结束,没有找到反例
        return true;
    }
}

2.二叉树遍历

2.二叉树遍历
在这里插入图片描述
根据题意画出该二叉树的结构:
在这里插入图片描述
代码实现:

package bin_tree.NewCoder;

import java.util.Scanner;

// 根据先序遍历结果还原二叉树,输出中序遍历结果
public class KY11 {
    private static class TreeNode {
        char val;
        TreeNode left;
        TreeNode right;
        public TreeNode(char val) {
            this.val = val;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 获取用户多组输入
        while (scanner.hasNext()) {
            // 字符串形式的先序二叉树结果
            String line = scanner.next();
            // str -> TreeNode
            TreeNode root = build(line);
            // 中序遍历二叉树,按照格式打印结点值
            inOrder(root);
            // 每个结果占一行
            System.out.println();
        }
    }

    private static void inOrder(TreeNode root) {
        if (root == null)
            return;
        inOrder(root.left);
        System.out.print(root.val +" ");
        inOrder(root.right);
    }

    // 根据先序遍历结果字符串还原二叉树,返回构建后二叉树的根节点
    private static TreeNode build(String line) {
        return preOrderBuild(line);
    }
    // abc##de#g##f###
    // str -> char
    // 当前处理到哪个字符了
    static int index = 0;
    private static TreeNode preOrderBuild(String line) {
        char c = line.charAt(index);
        if (c == '#') {
            return null;
        }
        TreeNode root = new TreeNode(c);
        index ++;
        root.left = preOrderBuild(line);
        index ++;
        root.right = preOrderBuild(line);
        return root;
    }
}

运行截图:
在这里插入图片描述

3.从前序与中序遍历序列构造二叉树

3.从二叉树与中序遍历序列构造二叉树

前序遍历:第一个节点一定是当前树的根节点,后序节点也是左树或右树的根节点。
中序遍历:左子树在根节点左侧,右子树在根节点右侧。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
1.代码实现:

package bin_tree.leetcode;

/**
 * 根据前序和中序遍历结果,还原二叉树
 */
public class Num105 {
    //当前处理到前序遍历的哪个位置了
    int index=0;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTreeInternal(preorder, inorder, 0, inorder.length);
    }

    /**
     * 根据传入的前序遍历和中序遍历的部分区间
     * [left,right) 表示当前节点中序遍历结果
     * 左区间连接到根节点左侧
     * 右区间连接到根节点右侧
     * @param preOrder 前序遍历结果
     * @param inOrder 中序遍历结果
     * @param left
     * @param right
     * @return
     */
    public TreeNode buildTreeInternal(int[] preOrder,int[] inOrder,int left,int right){
        //边界
        if(left >=right){
            //空区间,说明此时中序结果为空,空树
            return null;
        }
        if(index >= preOrder.length){
            //所有的节点已经全部处理完毕
            return null;
        }
        //此时前序结果还有没处理的元素,从Index取得一个元素构建根节点
        TreeNode root=new TreeNode(preOrder[index]);
        //继续处理下一个节点
        index++;
        //处理左树
        //拿着这个root.val去中序遍历中找到该值对应的索引pos
        int pos=find(inOrder,left,right,root.val);
        //左树
        root.left=buildTreeInternal(preOrder,inOrder,left,pos);
        //右树
        root.right=buildTreeInternal(preOrder,inOrder,pos+1,right);
        return root;

    }

    /**
     * 在当前中序遍历中寻找root.val对应的索引值
     * @param inOrder
     * @param left
     * @param right
     * @param val
     * @return
     */
    private int find(int[] inOrder, int left, int right, int val) {
        for (int i = left; i <right ; i++) {
            if (inOrder[i]==val){
                return i;
            }
        }
        return -1;
    }
}

在这里插入图片描述

4.从中序与后续遍历序列构造二叉树

4.从中序与后续遍历序列构造二叉树
在这里插入图片描述

在这里插入图片描述

package bin_tree.leetcode;

import java.util.HashMap;
import java.util.Map;

/**
 * 后序 + 中序
 **/
public class Num106 {
    // 存储中序遍历的对应的值和索引
    Map<Integer,Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        // 将后序遍历结果反转
        int[] preOrder = reverse(inorder,postorder);
        return buildTreeInternal(preOrder,inorder,0,inorder.length);
    }
    int index = 0;
    public TreeNode buildTreeInternal(int[] preOrder,int[] inOrder,int left,int right) {
        if(left >= right) {
            return null;
        }
        if (index >= preOrder.length) {
            return null;
        }
        TreeNode root = new TreeNode(preOrder[index]);
        index ++;
        int pos = map.get(root.val);
        root.right = buildTreeInternal(preOrder,inOrder,pos + 1,right);
        root.left = buildTreeInternal(preOrder,inOrder,left,pos);
        return root;
    }

    private int[] reverse(int[] inorder,int[] postorder) {
        int[] ret = new int[postorder.length];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = postorder[ret.length - 1 - i];
        }
        for (int i = 0; i < inorder.length; i++) {
            map.put(inorder[i],i);
        }
        return ret;
    }
}

在这里插入图片描述

5.二叉树的最近公共祖先

5.二叉树的最近公共祖先
在这里插入图片描述
在这里插入图片描述

package bin_tree.leetcode;

/**
 * 找二叉树的最近公共祖先
 **/
public class Num236 {
    TreeNode lca;
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) {
            return null;
        }
        // 从根节点出发进行后序遍历,找到lca(p和q出现在三个位置的两个)
        find(root,p,q);
        return lca;
    }
    // 在以root为根节点的二叉树中,是否能同时找到p和q
    private boolean find(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) {
            return false;
        }
        int left = find(root.left,p,q) ? 1 : 0;
        int right = find(root.right,p,q) ? 1 : 0;
        int mid = (root == p || root == q) ? 1 : 0;
        if (left + right + mid == 2) {
            lca = root;
            return true;
        }
        return (left + right + mid) > 0;
    }
}

在这里插入图片描述

6.根据二叉树创建字符串

6.根据二叉树创建字符串
在这里插入图片描述
在这里插入图片描述

package bin_tree.leetcode;

/**
 * 二叉树转为字符串
 **/
public class Num606 {
    StringBuilder sb = new StringBuilder();
    // "1(2(4))(3)"
    public String tree2str(TreeNode root) {
        if (root == null) {
            return "";
        }
        preOrder(root);
        return sb.toString();
    }
    private void preOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        // "1(2(4))(3)"
        sb.append(root.val);
        if (root.left != null) {
            sb.append("(");
            // 先序遍历左树
            preOrder(root.left);
            sb.append(")");
        }else {
            // 左空,判断右树是否为空
            if (root.right != null) {
                sb.append("()");
            }
        }
        if (root.right != null) {
            sb.append("(");
            preOrder(root.right);
            sb.append(")");
        }
    }
}

在这里插入图片描述

7.二叉搜索树与双向链表

在这里插入图片描述

package bin_tree.NewCoder;

import bin_tree.leetcode.TreeNode;

/**
 * 将二分搜索树转为排序的双向链表
 **/
public class ConvertTree2LinkedList {
    // 传入一个BST的根节点,就可以将其转为双向链表,且返回链表头
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null ||(pRootOfTree.left == null &&
                pRootOfTree.right == null)) {
            return pRootOfTree;
        }
        //先转换左子树
        TreeNode left = Convert(pRootOfTree.left);
        //将左子树的尾部与根节点连接
        TreeNode leftTail = left;
        while (leftTail != null && leftTail.right != null) {
            leftTail = leftTail.right;
        }
        //此时leftTail指向左链表的尾部
        //连接左链表尾部和根节点
        //判空
        if (leftTail != null) {
            leftTail.right = pRootOfTree;
            pRootOfTree.left = leftTail;
        }
        //继续转化右子树
        TreeNode right = Convert(pRootOfTree.right);
        //将根节点和右子树连接起来
        if (right != null) {
            right.left = pRootOfTree;
            pRootOfTree.right = right;
        }
        return left == null ? pRootOfTree : left;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ZJHFOREVERZJ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值