• Java二叉树超详解(常用方法介绍)(2)


    二叉树中的常用方法

    静态二叉树的手动创建

    这里我们先给出二叉树结点的信息(这里是内部类):

    1. static class TreeNode {
    2. public char val;
    3. public TreeNode left;//左孩子的引用
    4. public TreeNode right;//右孩子的引用
    5. public TreeNode(char val) {
    6. this.val = val;
    7. }
    8. }

    手动创建的代码如下:

    1. /**
    2. * 创建一棵二叉树 创建成功后 返回根节点
    3. * @return
    4. */
    5. public TreeNode createTree() {
    6. TreeNode A = new TreeNode('A');
    7. TreeNode B = new TreeNode('B');
    8. TreeNode C = new TreeNode('C');
    9. TreeNode D = new TreeNode('D');
    10. TreeNode E = new TreeNode('E');
    11. TreeNode F = new TreeNode('F');
    12. TreeNode G = new TreeNode('G');
    13. TreeNode H = new TreeNode('H');
    14. A.left = B;
    15. A.right = C;
    16. B.left = D;
    17. B.right = E;
    18. C.left = F;
    19. C.right = G;
    20. E.right = H;
    21. return A;
    22. }

    利用new出结点对象和左右指针的连接,我们就可以创建一棵这样的简单二叉树。(给你们画了个图嘿嘿)。

     获取树中结点的个数

    这里依然是用到了树的递归的思想:我们可以使用递归左树右树的方法,利用一个常量来记录结点的个数。

    1. public static int nodeSize;
    2. /**
    3. * 获取树中节点的个数:遍历思路
    4. */
    5. void size(TreeNode root) {
    6. if(root == null) {
    7. return;
    8. }
    9. nodeSize++;
    10. size(root.left);
    11. size(root.right);
    12. }

    但是更推荐用子问题的思想,即:一棵树的结点个数 = 左树的结点个数 + 右数的节点个数+ 根结点(即1),像这种利用递归方法的返回值计算我们就称为子问题思路。代码如下:

    1. /**
    2. * 获取节点的个数:子问题的思路
    3. *
    4. * @param root
    5. * @return
    6. */
    7. int size2(TreeNode root) {
    8. if(root == null) {
    9. return 0;
    10. }
    11. return size2(root.left) + size2(root.right) + 1;
    12. }

    获取叶子结点的个数

    求叶子结点,在代码上,就是求含有多少左边和右边都是null的节点数(如果一个节点满足这样的条件就++),像上面一样,先给出遍历的方法:

    1. /*
    2. 获取叶子节点的个数:遍历思路
    3. */
    4. public static int leafSize = 0;
    5. void getLeafNodeCount1(TreeNode root) {
    6. if(root == null) {
    7. return;
    8. }
    9. if(root.right == null && root.left == null) {
    10. leafSize++;
    11. }
    12. getLeafNodeCount1(root.left);
    13. getLeafNodeCount1(root.right);
    14. }

    下面是子问题的思路:

    1. /*
    2. 获取叶子节点的个数:子问题
    3. */
    4. int getLeafNodeCount2(TreeNode root) {
    5. if(root == null) {
    6. return 0;
    7. }
    8. int leftCount = getLeafNodeCount2(root.left);
    9. int rightCount = getLeafNodeCount2(root.right);
    10. //满足条件:即左右返回值+1, 不满足条件:还是给出原来的左右返回值
    11. return root.right == null && root.right == null ? leftCount + rightCount + 1 : leftCount + rightCount;
    12. }

    获取一棵树第k层的节点数目

    还是主要利用递归的思想:一棵树第k层的结点数 = 左树第k-1层的节点数 + 右树第k-1层的节点数。递归的截止条件就是:当k为1时,直接返回1即可,如果为空则返回0。那么所以,代码如下:

    1. /*
    2. 获取第K层节点的个数
    3. */
    4. int getKLevelNodeCount(TreeNode root, int k) {
    5. if(root == null) {
    6. return 0;
    7. }
    8. if(k == 1) {
    9. return 1;
    10. }
    11. //获取左树第k-1层的节点数
    12. int leftCount = getKLevelNodeCount(root.left, k - 1);
    13. //获取右树第k-1层的节点数
    14. int rightCount = getKLevelNodeCount(root.right, k - 1);
    15. //返回左右树之和
    16. return leftCount + rightCount;
    17. }

    获取二叉树的深度

    还是利用递归的思想(截止条件:为空返回零):一棵二叉树的深度 = 左树和右树之中最高的那一个的深度 + 1.

    利用我们之前学的子问题思想和递归,可以轻松写出: 

    1. int getHeight(TreeNode root) {
    2. if(root == null) {
    3. return 0;
    4. }
    5. int leftHeight = getHeight(root.left);
    6. int rightHeight = getHeight(root.right);
    7. //返回深度最大的那一个的深度 + 1
    8. return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
    9. }

     检查树中是否有值为value的结点(即返回该节点)

    还是利用之前的递归思路:value可能在当前结点,也可能在左右树当中,亦有可能不存在。

    这里一定要注意一个点:如果已经提前找到了目标节点,就直接返回即可(比如在左树当中找到了,就不用在右树当中找了),这样做可以大大节约时间

    1. // 检测值为value的元素是否存在
    2. TreeNode find(TreeNode root, char val) {
    3. if(root == null) {
    4. return null;
    5. }
    6. if(root.val == val) {
    7. return root;
    8. }
    9. TreeNode ret1 = find(root.left, val);
    10. //不再去右边了
    11. if(ret1 != null) {
    12. return ret1;
    13. }
    14. TreeNode ret2 = find(root.right, val);
    15. if(ret2 != null) {
    16. return ret2;
    17. }
    18. return null;
    19. }

     层序遍历

    层序遍历,在上一篇中我也有讲,就是对一棵树进行从上到下,从左到右的遍历操作。那么如何通过代码来实现这一个过程呢?这时我们就可以用到之前的一个数据结构,也就是队列,那么我们如何利用队列来进行层序遍历呢,我们来看下面:

    这里注意一个点,当且仅当左/右儿子不为空时,才能批准放入队列,否则跳过。代码如下: 

     

    1. //层序遍历(利用队列)
    2. void levelOrder(TreeNode root) {
    3. Queue queue = new LinkedList<>();
    4. queue.offer(root);
    5. //当队列不为空时持续该过程
    6. while(!queue.isEmpty()) {
    7. TreeNode cur = queue.poll();
    8. System.out.print(cur.val + " ");
    9. if(cur.left != null) {
    10. queue.offer(cur.left);
    11. }
    12. if(cur.right != null) {
    13. queue.offer(cur.right);
    14. }
    15. }
    16. }

    判断一棵树是否为完全二叉树

    我们来回顾一下完全二叉树的性质:即完全二叉树是一棵从上到下,从左到右依次排列元素的树(即直到最后一个结点之后,其余前面的结点都不能为空)。所以我们就浮现出了这样的思路,即还是利用队列来遍历树每次,都将左右儿子放入队列(不论是不是空),当遇到了第一个为空的元素后,立刻停止放入,检查队列中剩余的元素是否有非空的,如果全是null,则是完全二叉树,如果有一个不是,就不是完全二叉树,画图如下:

    代码如下:

    1. // 判断一棵树是不是完全二叉树
    2. boolean isCompleteTree(TreeNode root) {
    3. if(root == null) {
    4. return true;
    5. }
    6. Queue queue = new LinkedList<>();
    7. queue.offer(root);
    8. while(!queue.isEmpty()) {
    9. TreeNode cur = queue.poll();
    10. while(cur == null && !queue.isEmpty()) {
    11. TreeNode t = queue.poll();
    12. if(t != null) {
    13. return false;
    14. }
    15. }
    16. queue.offer(cur.left);
    17. queue.offer(cur.right);
    18. }
    19. return true;
    20. }

     

  • 相关阅读:
    mysql_命令行启动_win10
    解决“该扩展程序未列在 Chrome 网上应用店中,并可能是在您不知情的情况下添加的”的方法
    这篇文章用三分钟告诉你怎么把录音转文字
    AE 的软件、硬件、驱动控制、调试策略(没有算法)
    Ace编辑器
    Character.AI:产品优势和商业壁垒在哪里?
    如何在不结束tcpdump的情况下复制完整的pcap
    【python】程序常见异常&异常处理方法
    MongoDB系列之Linux环境部署配置
    每日一题leetcode--删除并获得点数(DP)
  • 原文地址:https://blog.csdn.net/asdssadddd/article/details/133775058