Java语言----二叉树

news2024/11/24 6:45:58

目录

一、二叉树

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<n ,左孩子序号: 2i+1 ,否则无左孩子
        若2i+2<n ,右孩子序号: 2i+2 ,否则无右孩子

二 、二叉树的实现

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

2.1第一种 使用数组

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

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

2.2第二种 使用链表实现

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

 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/579551.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spark入门介绍

目录 一、Spark框架概述 1、Spark简介 2、发展 二、Spark功能及特点 1、定义

Kubernetes部署+kubesphere管理平台安装

Kubernetes官网&#xff1b;kubesphere官网 不论是Kubernetes官网还是找的其它部署步骤&#xff0c;基本都是推荐搭建集群的方式&#xff0c;是为了实现高可用.....等等&#xff0c;这样一来至少需要两台或三台的服务器来搭建&#xff0c;这样对我们的成本也是非常大的&#xf…

HCIA-MSTP替代技术之链路捆绑(手工模式)

目录 1&#xff0c;网络的可靠性需求 2&#xff0c;链路聚合原理 链路聚合&#xff1a; 聚合组(Link Aggregation Group&#xff0c;LAG)&#xff1a; 成员接口和成员链路&#xff1a; 活动接口和活动链路&#xff1a; 非活动接口和非活动链路&#xff1a; 聚合模式&…

应急响应-web

应急响应的流程分为6个阶段 PDCERF 准备 &#xff0c;检测&#xff0c;抑制&#xff0c;根除&#xff0c;恢复&#xff0c;总结 准备&#xff1a; 准备阶段就是以预防为主&#xff0c;准备一些应急响应的预案&#xff0c;对应急响应的分工操作制定一些计划&#xff0c;进行应…

Redis的数据结构

一)SDS 在redis中&#xff0c;保存key的是字符串&#xff0c;value往往是字符串或者是字符串的集合&#xff0c;可见字符串是redis中最常用的一种数据结构: 但是在redis中并没有直接使用C语言的字符串&#xff0c;因为C语言的字符串存在很多问题 1)获取字符串的长度需要通过运算…

突破自动化测试瓶颈!WEB自动化测试鼠标与键盘操作最佳实践分享

目录 引言 鼠标操作方法 说明 实例化对象 方法 实例1 实例2 拖拽 注意 键盘操作 说明 Keys类 常用的键盘操作 案例 结语 引言 在现代软件测试中&#xff0c;WEB自动化测试已经成为了必不可少的一部分&#xff0c;然而&#xff0c;面对各种繁琐的测试场景&#xf…

章节2: husky + 自动检测是否有未解决的冲突 + 预检查debugger + 自动检查是否符合commit规范

在章节1中我们学习到了commit的规范、husky的安装和使用、lint-staged怎么安装以及怎么用来格式化代码。那么这篇文章我们来看看commit预处理中我们还能做哪些处理呢&#xff1f; 自然&#xff0c;我们还是要用到husky这个东西的&#xff0c;大致过程其实和章节1异曲同工&#…

sql语句查询数据库字段和表字段数量

》新建数据库:CREATE DATABASE IF NOT EXISTS 数据库名; 示例&#xff1a;:CREATE DATABASE IF NOT EXISTS test_db; 》进入数据库&#xff1a;use 数据库名称&#xff1b; 示例&#xff1a;use test_db; 》数据库中创建表: create table 表名(字段名 字段类型(长度),字段名 字…

零基础自学黑客【网络安全】啃完这些足够了

我刚学网络安全&#xff0c;该怎么学&#xff1f;要学哪些东西&#xff1f;有哪些方向&#xff1f;怎么选&#xff1f; 怎么入门&#xff1f; 这个 Web 安全学习路线&#xff0c;整体大概半年左右&#xff0c;具体视每个人的情况而定。 &#xff08;上传一直很模糊&#xff0c…

网络安全做红队攻防 35 岁以后可以干嘛?

35岁之后不是都当技术总监&#xff0c;CTO了或者自己创业了吗&#xff1f; 不会&#xff0c;单渗透测试来说&#xff0c;到后期更多是经验的积累。同一个事情&#xff0c;经验老道师傅的可能用更少的命令&#xff0c;发更少的请求完成这个事情&#xff0c;更隐蔽&#xff0c;更…

从AI到BI:隐语SCQL深度解读(附视频)

3月29日,“隐语开源社区开放日”活动顺利举办。当天隐语社区正式开源SCQL引擎,在工业界首次实现了隐私数据从Al到BI分析,是隐语走向易用的重要一步!下文为隐语框架负责人王磊在活动现场的分享内容。 我们知道,在隐私计算目前应用较多的场景中,无论是风控场景的LR、XGB,还…

每日学术速递5.27

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Control-A-Video: Controllable Text-to-Video Generation with Diffusion Models 标题&#xff1a;Control-A-Video&#xff1a;使用扩散模型生成可控的文本到视频 作者&#xff…

vcruntime140.dll无法继续执行代码如何修复,使用这个方法不求人

VCRUNTIME140.dll 是由微软公司开发的一个库文件&#xff0c;属于 Visual C Redistributable 软件包的一部分。它包含了许多与 C 应用程序运行时相关的函数和数据类型。这些函数和数据类型包括内存管理、异常处理、文件 I/O 等等。如果您在运行某个程序时发现缺少了 VCRUNTIME1…

PriorityQueue优先级队列

前言 优先级队列就是在堆的基础上进行改造&#xff0c;那么什么是堆&#xff0c;又什么是优先级队列呢&#xff1f; 我们一起来看看吧&#xff01; 目录 前言 一、堆 &#xff08;一&#xff09;堆的创建 &#xff08;二&#xff09;堆的插入 &#xff08;三&#xff09;堆…

win10 nvprof的性能分析表

交叉访问是全局内存中最糟糕的访问模式&#xff0c;因为它浪费总线带宽 使用多个线程块对基于交叉的全局内存访问重新排序到合并访问 https://mp.weixin.qq.com/s/h2XKth1bTujnrxyXTJ2fwg <<<numBlocks, blockSize>>> 的两个参数应该怎么设置好呢。首先&…

lazada商品评论数据接口,支持多站点

可以使用Lazada的开放平台API来获取商品评论数据。以下是使用API获取Lazada商品评论数据的基本步骤&#xff1a; 1.注册Lazada开发者账号&#xff0c;创建API密钥和访问令牌。 2.调用Lazada Open API中的Product Review API&#xff0c;提供商品的SKU或Seller SKU参数&#x…

Spring Authorization Server 系列(二)获取授权码

Spring Authorization Server 系列&#xff08;二&#xff09;获取授权码 概述获取授权码获取授权码的url逻辑解析匹配url参数解析 三级目录 概述 Spring Authorization Server 是基于 OAuth2.1 和 OIDC 1.0 的。 只有 授权码&#xff0c;刷新token&#xff0c;客户端模式。 …

Python GUI:真的只知道PyQt?

B站|公众号&#xff1a;啥都会一点的研究生 有时候我们有需求将程序制作成GUI&#xff08;图形用户界面&#xff09;格式&#xff0c;以方便用户通过图形图标与电子设备进行交互&#xff0c;而大多数像我一样的小白基本上只知道PyQt&#xff0c;往往制作出来的界面一眼就可辨别…

如何编写快速高效的SQL查询(一)——MySQL8.0优化器查询优化处理与样例

当希望MySQL能够以更高的性能运行查询时&#xff0c;最好的办法就是弄清楚MySQL是如何优化和执行查询的。一旦理解了这一点&#xff0c;很多查询优化工作实际上就是遵循一些原则让优化器能够按照预想的合理的方式运行。 MySQL是如何执行一个查询的过程的&#xff1f;根据图8-1可…

SpringCloud高级篇 - 微服务保护

✨作者&#xff1a;猫十二懿 ❤️‍&#x1f525;账号&#xff1a;CSDN 、掘金 、个人博客 、Github &#x1f389;公众号&#xff1a;猫十二懿 学习课程视频 SpringCloud 高级篇 – 微服务保护 1.初识Sentinel 1.1.雪崩问题及解决方案 1.1.1.雪崩问题 微服务中&#xff0…