Java语言----二叉树

简介: Java语言----二叉树

😽个人主页: 博客-专业IT技术发表平台 (csdn.net)

🌈梦的目标:努力学习,向Java进发,拼搏一切,让自己的未来不会有遗憾。

🎁欢迎各位→点赞👍 + 收藏⭐ + 评论📝+关注✨

 本章讲解内容:二叉树


image.png

使用编译器:IDEA


一、二叉树


1.1 二叉树概念

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

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

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

image.png


重要知识:


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的结点在二叉树中的位置相同。

image.png



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

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


image.png



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+2


二 、二叉树的实现


实现方法为2种。

       第一种使用数组,顺序存储二叉树结点。

       第二种使用链表的链式存储。

        此处我们使用链表实现


2.1第一种 使用数组


image.png


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

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


2.2第二种 使用链表实现


image.png

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

2.2.1二叉树代码构建


public class BinaryTree{
    // 孩子表示法
    class Node {
      int val; // 数据域,代表结点的值
      Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
      Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
      Node(){}
      Node(int num)
     {
        this.val=num;
     }
  }
private Node root;
//构建二叉树
public void createBinaryTree(){
Node node1 = new Node(1);
Node node1 = new Node(2);
Node node1 = new Node(3);
Node node1 = new Node(4);
Node node1 = new Node(5);
Node node1 = new Node(6);
root = node1;
node1.left = node2;
node2.left = node3;
node1.right = node4;
node4.left = node5;
node5.right = node6;
}
// 获取树中节点的个数
public int size(Node root);
// 获取叶子节点的个数
public int getLeafNodeCount(Node root);
// 获取第K层节点的个数
public int getKLevelNodeCount(Node root,int k);
// 获取二叉树的高度
public int getHeight(Node root);
// 检测值为value的元素是否存在
public Node find(Node root, int val);
//层序遍历
public void levelOrder(Node root);
// 判断一棵树是不是完全二叉树
public boolean isCompleteTree(Node root);
}


2.2.2二叉树的基本操作

获取二叉树结点个数:

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


获取叶子结点个数:

// 获取叶子节点的个数
    public int getLeafNodeCount(Node root)
    {
        if(root==null)
        {
            return 0;
        }
        if(root.left==null&&root.right==null)
            return 1;
        return getLeafNodeCount(root.left)+getLeafNodeCount(root.right);
    }


获取第k层结点个数:

public int getKLevelNodeCount(TreeNode root, int k) {
        if(root == null) {
            return 0;
        }
        if(k == 1) {
            return 1;
        }
        return getKLevelNodeCount(root.left,k-1)
                + getKLevelNodeCount(root.right,k-1);
    }


获取二叉树高度:

public  int getHeight(TreeNode root) {
        if(root == null) {
            return 0;
        }
        int leftH = getHeight(root.left);
        int rightH = getHeight(root.right);
        return (leftH > rightH ? leftH :rightH) + 1;
    }

检测是否存在value值:

 public TreeNode find(TreeNode root,int val) {
        if(root == null) return null;
        if(root.val == val) {
            return root;
        }
        TreeNode leftL = find(root.left,val);
        if(leftL != null) {
            return leftL;
        }
        TreeNode leftLR = find(root.right,val);
        if(leftLR != null) {
            return leftLR;
        }
        return null;
    }


层序遍历:

 public void levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
       if(root != null) {
           queue.offer(root);
       }
       while (!queue.isEmpty()) {
           TreeNode top = queue.poll();
           System.out.print(top.val+" ");
           if(top.left != null) {
               queue.offer(top.left);
           }
           if(top.right != null) {
               queue.offer(top.right);
           }
       }
    }


是否为完全二叉树:

 public boolean isCompleteTree(TreeNode root) {
        Queue<Node> queue = new LinkedList<>();
        if(root != null) {
            queue.offer(root);
        }
        while (!queue.isEmpty()) {
            Node cur = queue.poll();
            if(cur != null) {
                queue.offer(cur.left);
                queue.offer(cur.right);
            }else {
                break;
            }
        }
        while (!queue.isEmpty()) {
           Node cur = queue.poll();
            if(cur != null) {
                return false;
            }
        }
        return true;
    }


三、二叉树的三种遍历


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


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


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


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


网络异常,图片无法展示
|


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

前序遍历:

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


中序遍历:

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


后序遍历:

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


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

前序遍历:

public void preOrderIteration(TreeNode head) {
    if(head==null){
       return;
    }
Stack<TreeNode> stack=new Stack<>();
stack.push(head);
    while(!stack.isEmpty())
    {
        TreeNOde node=stack.pop();
        System.out.print(node.val+" ");
        if(node.right!=null)
        {
            stack.push(node.left);
        }
        if(node.left!=null){
            stack.push(node.right);
        }
    }
}


利用栈的原理

中序遍历:

 public void inOrderIteration(TreeNode head) {
    if(head==null){
       return;
    }
    Stack<TreeNode> stack=new Stack<>();
    TreeNode cur=head;
    while(!stack.isEmpty())
    {
        while(cur!=null)
        {
          stack.push(cur);
          cur=cur.left;
        }
        TreeNode node=stack.pop();
        System.out.print(node.val+"");
        if(node.right!=null)
        {
            cur=node.right;
        }
    }
}


后序遍历:

public static void postOrderIteration(TreeNode head) {
        if (head == null) {
            return;
        }
        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();
        stack1.push(head);
        while (!stack1.isEmpty()) {
            TreeNode node = stack1.pop();
            stack2.push(node);
            if (node.left != null) {
                stack1.push(node.left);
            }
            if (node.right != null) {
                stack1.push(node.right);
            }
        }
        while (!stack2.isEmpty()) {
            System.out.print(stack2.pop().val + " ");
        }
    }


总结


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


目录
相关文章
|
3月前
|
JSON JavaScript 前端开发
Python+JAVA+PHP语言,苏宁商品详情API
调用苏宁商品详情API,可通过HTTP/HTTPS发送请求并解析响应数据,支持多种编程语言,如JavaScript、Java、PHP、C#、Ruby等。核心步骤包括构造请求URL、发送GET/POST请求及解析JSON/XML响应。不同语言示例展示了如何获取商品名称与价格等信息,实际使用时请参考苏宁开放平台最新文档以确保兼容性。
|
3月前
|
监控 Java API
Java语言按文件创建日期排序及获取最新文件的技术
这段代码实现了文件创建时间的读取、文件列表的获取与排序以及获取最新文件的需求。它具备良好的效率和可读性,对于绝大多数处理文件属性相关的需求来说足够健壮。在实际应用中,根据具体情况,可能还需要进一步处理如访问权限不足、文件系统不支持某些属性等边界情况。
209 14
|
4月前
|
Java 编译器 应用服务中间件
为什么说 Java 语言编译与解释并存的原因
在编程语言的世界里,Java以其独特的“编译与解释并存”特性独树一帜。这一特性不仅赋予了Java强大的跨平台能力,还使其在性能和灵活性上达到了很好的平衡。接下来,我们将深入探讨Java语言这一特性的本质、原理以及在实际应用中的体现。
97 6
|
4月前
|
分布式计算 Java 大数据
Java 语言基础概念与常识之主要特点解析
Java是一种广泛应用于企业级开发、移动应用(如Android)、大数据处理及云计算等领域的编程语言。其核心特点包括跨平台性(一次编写,到处运行)、面向对象设计、自动垃圾回收、多线程支持和高性能表现。Java通过JVM实现跨平台,具备强大的健壮性和安全性,同时拥有丰富的标准库与活跃的开发者社区。本文深入解析Java的技术优势及其在电商系统、大数据处理和云计算中的实际应用,并提供相关面试资料供学习参考。
128 0
|
4月前
|
网络协议 安全 Java
实现Java语言的文件断点续传功能的技术方案。
像这样,我们就完成了一项看似高科技、实则亲民的小工程。这样的技术实现不仅具备实用性,也能在面对网络不稳定的挑战时,稳稳地、不失乐趣地完成工作。
253 0
|
6月前
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
212 5
|
7月前
|
存储 Java 数据安全/隐私保护
Java语言位运算符详解
Java语言提供了7种位运算符:按位与(&)、按位或(|)、按位异或(^)、取反(~)、左移(&lt;&lt;)、带符号右移(&gt;&gt;)和无符号右移(&gt;&gt;&gt;)。这些运算符主要用于对long、int、short、byte和char类型的数据进行二进制位级别的操作,不能用于double、float和boolean类型。文中详细讲解了每种运算符的规则和应用场景,并指出位运算在实际开发中有重要应用价值,不仅限于面试。
299 2
|
7月前
|
Java 开发者
课时2:Java语言特点
课时2介绍了Java语言的多个关键特性。作为开源且半开源的产品,Java成为通用技术标准,拥有透明的开发环境。其面向对象的设计、自动内存回收、简化指针处理(使用引用)、支持多线程编程、高效的网络处理能力(如NIO)及良好的可移植性,共同促成了Java的强大生态系统和广泛应用。
|
8月前
|
存储 缓存 Java
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
823 3
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
|
8月前
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
1345 5

热门文章

最新文章