• Java语言----二叉树


    目录

    一、二叉树

    1.1 二叉树概念

    1.2 两种特殊的二叉树

    1.3二叉树的性质

    二 、二叉树的实现

    2.1第一种 使用数组

    2.2第二种 使用链表实现

     2.2.1二叉树代码构建

     2.2.2二叉树的基本操作

    三、二叉树的三种遍历

    3.1递归方法实现 前、中、后遍历

    3.2非递归方法实现 前、中、后遍历

    总结


    😽个人主页: 博客-专业IT技术发表平台 (csdn.net)
     🌈梦的目标:努力学习,向Java进发,拼搏一切,让自己的未来不会有遗憾。
     🎁欢迎各位→点赞👍 + 收藏⭐ + 评论📝+关注✨
      本章讲解内容:二叉树

    来源百度
    来源于百度

      使用编译器:IDEA

    一、二叉树

    1.1 二叉树概念

    二叉树:一种 非线性 的数据结构,为结点的一个有限集合

                  有限集合分类:1、或者为空     

                                            2、由一个根节点加上两棵别称为 左子树 和 右子树 的二叉树组成

    重要知识:

    1、树的深度或高度:树的最大层次。如上图:该二叉树高度为3

    2、结点的度:1个结点含有的子树个数。如上图:结点1的度为2,分别为2和4的左右子树。

    3、父亲结点:拥有子树的结点。如上图:1便有2和4的子树,所以为父亲结点。

    4、孩子结点:一个结点的的子树结点便为孩子结点。如上图:2是1的孩子结点

    5、叶子结点:无子树的结点。如上图:3、5、6的结点无子树,为叶子结点。

    6、根结点:最开始的结点。如上图:1为根结点,每个二叉树只有一个根结点。

    1.2 两种特殊的二叉树

    1. 满二叉树 : 一棵二叉树,如果 每层的结点数都达到最大值,则这棵二叉树就是满二叉树 。也就是说, 如果一棵 二叉树的层数为K,且结点总数是  2^k-1 则它就是满二叉树。

    2. 完全二叉树 : 一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,从0开始编号,编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同。

    红色数字,代表的是结点序号,数组实现时使用 

    完全二叉树更为重要,因为便是在此基础上实现的。


    1.3二叉树的性质

    1. 若规定 根结点的层数为 1 ,则一棵 非空二叉树的第 i 层上最多有 (i>0) 个结点
    2. 若规定只有 根结点的二叉树的深度为 1 ,则 深度为 K 的二叉树的最大结点数是 (k>=0)
    3. 对任何一棵二叉树 , 如果其 叶结点个数为 n0, 度为 2 的非叶结点个数为 n2, 则有 n0 n2 1
    4. 具有 n 个结点的完全二叉树的深度k为 log2(n+1)  上取整
    5. 对于具有 n 个结点的完全二叉树 ,如果按照 从上至下从左至右的顺序对所有节点从 0 开始编号, 则对于 序号为 i 的结点有
            若i>0 双亲序号: (i-1)/2 i=0 i 为根结点编号 ,无双亲结点
            若2i+1 ,左孩子序号: 2i+1 ,否则无左孩子
            若2i+2 ,右孩子序号: 2i+2 ,否则无右孩子

    二 、二叉树的实现

    实现方法为2种。
            第一种使用数组,顺序存储二叉树结点。
            第二种使用链表的链式存储。
             此处我们使用链表实现

    2.1第一种 使用数组

     红色标注的是结点的下标值,一层一层放入array数组里。

     特点:父结点=(孩子结点-1) / 2   此时的结点 等于 数组的下标值。

    2.2第二种 使用链表实现

     二叉树的链式存储:通过一个一个的节点引用起来的,因此可以通过链表的方式实现。

     2.2.1二叉树代码构建

    1. public class BinaryTree{
    2. // 孩子表示法
    3. class Node {
    4. int val; // 数据域,代表结点的值
    5. Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
    6. Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
    7. Node(){}
    8. Node(int num)
    9. {
    10. this.val=num;
    11. }
    12. }
    13. private Node root;
    14. //构建二叉树
    15. public void createBinaryTree(){
    16. Node node1 = new Node(1);
    17. Node node1 = new Node(2);
    18. Node node1 = new Node(3);
    19. Node node1 = new Node(4);
    20. Node node1 = new Node(5);
    21. Node node1 = new Node(6);
    22. root = node1;
    23. node1.left = node2;
    24. node2.left = node3;
    25. node1.right = node4;
    26. node4.left = node5;
    27. node5.right = node6;
    28. }
    29. // 获取树中节点的个数
    30. public int size(Node root);
    31. // 获取叶子节点的个数
    32. public int getLeafNodeCount(Node root);
    33. // 获取第K层节点的个数
    34. public int getKLevelNodeCount(Node root,int k);
    35. // 获取二叉树的高度
    36. public int getHeight(Node root);
    37. // 检测值为value的元素是否存在
    38. public Node find(Node root, int val);
    39. //层序遍历
    40. public void levelOrder(Node root);
    41. // 判断一棵树是不是完全二叉树
    42. public boolean isCompleteTree(Node root);
    43. }

    2.2.2二叉树的基本操作

    获取二叉树结点个数:

    1. public int size(Node root)
    2. {
    3. if(root==null)
    4. return 0;
    5. return size(root.left)+size(root.right)+1;
    6. }

    获取叶子结点个数:

    1. // 获取叶子节点的个数
    2. public int getLeafNodeCount(Node root)
    3. {
    4. if(root==null)
    5. {
    6. return 0;
    7. }
    8. if(root.left==null&&root.right==null)
    9. return 1;
    10. return getLeafNodeCount(root.left)+getLeafNodeCount(root.right);
    11. }

     获取第k层结点个数:

    1. public int getKLevelNodeCount(TreeNode root, int k) {
    2. if(root == null) {
    3. return 0;
    4. }
    5. if(k == 1) {
    6. return 1;
    7. }
    8. return getKLevelNodeCount(root.left,k-1)
    9. + getKLevelNodeCount(root.right,k-1);
    10. }

     获取二叉树高度:

    1. public int getHeight(TreeNode root) {
    2. if(root == null) {
    3. return 0;
    4. }
    5. int leftH = getHeight(root.left);
    6. int rightH = getHeight(root.right);
    7. return (leftH > rightH ? leftH :rightH) + 1;
    8. }

    检测是否存在value值:

    1. public TreeNode find(TreeNode root,int val) {
    2. if(root == null) return null;
    3. if(root.val == val) {
    4. return root;
    5. }
    6. TreeNode leftL = find(root.left,val);
    7. if(leftL != null) {
    8. return leftL;
    9. }
    10. TreeNode leftLR = find(root.right,val);
    11. if(leftLR != null) {
    12. return leftLR;
    13. }
    14. return null;
    15. }

    层序遍历:

    1. public void levelOrder(TreeNode root) {
    2. Queue queue = new LinkedList<>();
    3. if(root != null) {
    4. queue.offer(root);
    5. }
    6. while (!queue.isEmpty()) {
    7. TreeNode top = queue.poll();
    8. System.out.print(top.val+" ");
    9. if(top.left != null) {
    10. queue.offer(top.left);
    11. }
    12. if(top.right != null) {
    13. queue.offer(top.right);
    14. }
    15. }
    16. }

     是否为完全二叉树:

    1. public boolean isCompleteTree(TreeNode root) {
    2. Queue queue = new LinkedList<>();
    3. if(root != null) {
    4. queue.offer(root);
    5. }
    6. while (!queue.isEmpty()) {
    7. Node cur = queue.poll();
    8. if(cur != null) {
    9. queue.offer(cur.left);
    10. queue.offer(cur.right);
    11. }else {
    12. break;
    13. }
    14. }
    15. while (!queue.isEmpty()) {
    16. Node cur = queue.poll();
    17. if(cur != null) {
    18. return false;
    19. }
    20. }
    21. return true;
    22. }

    三、二叉树的三种遍历

    二叉树有四种遍历方法:前序遍历、中序遍历、后序遍历已经层序遍历。

    前序遍历:访问根结点--->根的左子树--->根的右子树         (根-左-右)

    中序遍历:根的左子树--->根节点--->根的右子树                (左-根-右)

    后序遍历:根的左子树--->根的右子树--->根节点                (左-右-根)

    3.1递归方法实现 前、中、后遍历

    前序遍历:

    1. public void preOrder(TreeNode root) {
    2. if(root == null) return;
    3. System.out.print(root.val+" ");
    4. preOrder(root.left);
    5. preOrder(root.right);
    6. }

    中序遍历:

    1. public void inOrder(TreeNode root) {
    2. if(root == null) return;
    3. inOrder(root.left);
    4. System.out.print(root.val+" ");
    5. inOrder(root.right);
    6. }

    后序遍历:

    1. public void postOrder(TreeNode root) {
    2. if(root == null) return;
    3. postOrder(root.left);
    4. postOrder(root.right);
    5. System.out.print(root.val+" ");
    6. }

    3.2非递归方法实现 前、中、后遍历

    前序遍历:

    1. public void preOrderIteration(TreeNode head) {
    2. if(head==null){
    3. return;
    4. }
    5. Stack stack=new Stack<>();
    6. stack.push(head);
    7. while(!stack.isEmpty())
    8. {
    9. TreeNOde node=stack.pop();
    10. System.out.print(node.val+" ");
    11. if(node.right!=null)
    12. {
    13. stack.push(node.left);
    14. }
    15. if(node.left!=null){
    16. stack.push(node.right);
    17. }
    18. }
    19. }

    利用栈的原理

    中序遍历:

    1. public void inOrderIteration(TreeNode head) {
    2. if(head==null){
    3. return;
    4. }
    5. Stack stack=new Stack<>();
    6. TreeNode cur=head;
    7. while(!stack.isEmpty())
    8. {
    9. while(cur!=null)
    10. {
    11. stack.push(cur);
    12. cur=cur.left;
    13. }
    14. TreeNode node=stack.pop();
    15. System.out.print(node.val+"");
    16. if(node.right!=null)
    17. {
    18. cur=node.right;
    19. }
    20. }
    21. }

    后序遍历:

    1. public static void postOrderIteration(TreeNode head) {
    2. if (head == null) {
    3. return;
    4. }
    5. Stack stack1 = new Stack<>();
    6. Stack stack2 = new Stack<>();
    7. stack1.push(head);
    8. while (!stack1.isEmpty()) {
    9. TreeNode node = stack1.pop();
    10. stack2.push(node);
    11. if (node.left != null) {
    12. stack1.push(node.left);
    13. }
    14. if (node.right != null) {
    15. stack1.push(node.right);
    16. }
    17. }
    18. while (!stack2.isEmpty()) {
    19. System.out.print(stack2.pop().val + " ");
    20. }
    21. }

    总结

             无论是链表实现,还是数组实现,各有其优势,不同情况使用,而不是代表链表实现比数组更好。二叉树里最重要的是完全二叉树,而在它基础上又实现了另一个数据结构,。在Java中更含有对应的实现类 PriorityQueue

  • 相关阅读:
    [GAMES101]透视投影变换矩阵中为什么需要改变z值
    学习记录-Python的局部变量和全局变量
    【论文笔记】LoRA LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS
    3.机器学习-十大算法之一线性回归算法(LinearRegression)原理讲解
    VBA将当前打开的表格生成PDF图片
    【C++】详细讲解函数使用,带你玩转C++函数~
    序列到序列学习(seq2seq)
    Nuxt.js头部魔法:轻松自定义页面元信息,提升用户体验
    C++第一天:C++面向对象高级开发上
    错题汇总14
  • 原文地址:https://blog.csdn.net/m0_74097410/article/details/130831137