认识二叉树

news2024/11/19 20:17:59

hi,代噶候。今天带大家认识一下二叉树,这个二叉树在我看来确实很有难度,但是不要怕,,鲁迅先生曾经说过,真正的勇士敢于面对惨淡的人生,敢于正视淋漓 的鲜血,下面让我们开始吧,先看看大纲

🚀1.什么是树

🚀2.树的相关概念

🚀3.什么是二叉树

🚀4.二叉树的相关概念

🚀5.二叉树的基本操作

什么是树呢???

树是一种非线性的结构,由n个结点组成,之所以叫做树,是因为它是根朝上,叶子朝下的结构,和现实中的树很像。

树的几个注意的点

1.一棵树只有一个根节点

2.树和链表不一样。没有所谓的前驱,只有左树和右树

3.树是递归实现的

现在对树的相关概念进行介绍

1.结点的度:树的子树的个数 ,上图中A的度为2

2.树的度:所有节点数的最大值叫做树的度,上图中树的度为5

3.叶子结点:没有左子树并且没有右子树

4.双亲结点:若一个结点有孩子结点,那么该结点为双亲节点

5.孩子结点:双亲结点的孩子叫做孩子结点

6.根节点:没有父亲结点的结点;

7.树的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推

8.树的高度或深度:结点的最大层次
树要怎么表示呢
有双亲表示法
孩子表示法
孩子双亲表示法
孩子兄弟表示法
class Node {
int value ; //树的存储的值
Node fifirstChild ;//第一个孩子引用
Node nextBrother ; //第二个孩子引用

这个了解即可

现在重头戏来了:二叉树来了

先了解一下二叉树的概念

就是每个结点的度不能超过2的树

画个图

 这个图就是一个二叉树

满二叉树:

二叉树的每一个结点都有左子树和右子树

如图

 

完全二叉树

不一定满。但是在进行层次遍历的时候顺序一定是相连的

在进行层次遍历的时候有1,2,3,4,5,6,7,8,9,10,11,12,13

这就是有序的

什么是无序的呢,再画个图

 

这就不是一个完全二叉树,不连续,11和13之间差一个12

由此可看,满二叉树是一种特殊的完全二叉树 

二叉树的性质

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

二叉树的存储

二叉树的存储分为链式存储额和顺序存储

今天先讲链式存储


//孩子表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
}

下面来说一说二叉树的遍历方式

1.前序遍历  根左右

2.中序遍历  左根右

3.后序遍历  左右根

4.层次遍历  从左至右

 就拿这棵树来举例

前序遍历:ABDGEHCF

中序遍历:GDBHEACF

后序遍历:GDHEBFCA

层次遍历:ABCDEFGH

还有一种考法,多出现在选择题里面,已知前序和中序,求后序。或者已知中序和后序,求前序

下面是二叉树的基本操作

 public class BinaryTree {

    static class TreeNode {
        public char val;
        public TreeNode left;//左孩子的引用
        public TreeNode right;//右孩子的引用

        public TreeNode(char val) {
            this.val = val;
        }
    }
    public TreeNode root;



    /**
     * 创建一棵二叉树 返回这棵树的根节点
     *
     * @return
     */
    public TreeNode createTree() {
        TreeNode A=new TreeNode('A');
        TreeNode B=new TreeNode('B');
        TreeNode C=new TreeNode('C');
        TreeNode D=new TreeNode('D');
        TreeNode E=new TreeNode('E');
        TreeNode F=new TreeNode('F');
        TreeNode G=new TreeNode('G');
        TreeNode H=new TreeNode('H');
        A.left=B;
        B.left=D;
        B.right=E;
        C.left=F;
        C.right=G;
        E.right=H;
        this.root=A;
        return root;



    }

    // 前序遍历
    public void preOrder(TreeNode root) {
        if(root==null){
            return;
        }
        System.out.println(root.val+"");
       preOrder(root.left);
       preOrder(root.right);
    }

    // 中序遍历
    void inOrder(TreeNode root) {
        if(root==null){
            return;
        }
       inOrder(root.left);
        System.out.println(root.val+"");
        inOrder(root.right);

    }

    // 后序遍历
    void postOrder(TreeNode root) {
        if(root==null){
            return;
        }
        postOrder(root.left);
        System.out.println(root.val+"");
        postOrder(root.right);


    }

    public static int nodeSize;

    /**
     * 获取树中节点的个数:遍历思路
     */
    public int NodeSize;//成员变量
    void size(TreeNode root) {
        if(root==null){
            return;

        }
        NodeSize++;
       size(root.left);
       size(root.right);
    }

    /**
     * 获取节点的个数:子问题的思路
     *
     * @param root
     * @return
     */
    int size2(TreeNode root) {
        if(root==null){
            return -1;
        }
        int leftSize=size2(root.left);
        int rightSize=size2(root.right);
        return leftSize+rightSize+1;

    }


    /*
     获取叶子节点的个数:遍历思路
     */
    public static int leafSize = 0;//静态成员变量

    void getLeafNodeCount1(TreeNode root) {
        if(root==null){
            return;
        }
        if(root.left==null&&root.right==null){
            leafSize++;
        }
        getLeafNodeCount1(root.left);
        getLeafNodeCount1(root.right);

    }

    /*
     获取叶子节点的个数:子问题
     */
    int getLeafNodeCount2(TreeNode root) {
        if(root==null){
            return -1;
        }
        if(root.left==null&&root.right==null){
            return 1;
        }
        int leftSize=getLeafNodeCount2(root.left);
        int rightSize=getLeafNodeCount2(root.right);
        return leftSize+rightSize;

    }

    /*
    获取第K层节点的个数
     */
    int getKLevelNodeCount(TreeNode root, int k) {
        if(root==null){
            return -1;
        }
        if(k==1){
            return 1;
        }
         int leftSize=   getKLevelNodeCount(root.left,k-1);
      int rightSize=  getKLevelNodeCount(root.right,k-1);
      return leftSize+rightSize;



    }

    /*
     获取二叉树的高度
     时间复杂度:O(N)
     */
    int getHeight(TreeNode root) {
        if(root==null){
            return -1;
        }
        int leftHeight=getHeight(root.left);
        int  rightHeight=getHeight(root.right);
        return (leftHeight>rightHeight)?leftHeight+1:rightHeight+1;
    }


    // 检测值为value的元素是否存在
    TreeNode find(TreeNode root, char val) {
        if(root==null){
            return null;
        }
        if(root.val==val){
            return root;
        }
     TreeNode  leftNode=   find(root.left,val);

        if( leftNode!=null){
            return leftNode;
        }
        TreeNode  rightNode=find(root.right,val);
     if(rightNode!=null){
            return rightNode;
        }

        return null;
    }

今天的分享先到这里,下期再见!!!

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

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

相关文章

线程池的内部结构与原理解析

线程池的内部结构 使⽤线程池的原因&#xff1a; 1、降低资源消耗 2、控制并发的数量。并发数量过多&#xff0c;可能会导致资源消耗过多&#xff0c;从⽽造成服务器崩溃 3、提高线程的可管理性 1、线程是稀缺资源&#xff0c;如果无限制地创建&#xff0c;不仅会消耗系统资源&…

Global Illumination_SDF Generate Visualize Shadow

Signed Distance Field(有向距离场)&#xff0c;简称SDF&#xff0c;这其实是图形学中非常常用的数学概念。数学上来说&#xff0c;是定义在空间中的一个标量场&#xff0c;标量值为空间一点到曲面的距离。曲面外的点为正值&#xff0c;曲面上的点为0&#xff0c;曲面内的点为负…

通用vue组件化展示列表数据

一、数据的简单展示 1.首先先确定要展示的表格列名以及拿到所需要展示的数组数据 2.然后建立一个专门放el-table遍历的文件 3.在父组件中将数据列表数据存放在listData里面&#xff0c;然后传给子组件&#xff0c;子组件定义一个动态的列&#xff0c;通过遍历propList得到列名…

SpringCloud从入门到精通(八)

config config-概述 • Spring Cloud Config 解决了在分布式场景下多环境配置文件的管理和维护。 • 好处&#xff1a; 集中管理配置文件 不同环境不同配置&#xff0c;动态化的配置更新 配置信息改变时&#xff0c;不需要重启即可更新配置信息到服务config-快速入门 gitee搭…

一文告别结合Nacos后,Springboot的配置文件看不懂的痛苦

一、背景 后端基于SpringCloud项目架构的话&#xff0c;默认会使用Nacos来做配置中心&#xff0c;但是这对从来没接触过Nacos配置中心的小伙伴&#xff0c;肯定就不知道怎么回事了&#xff0c;于是便有了这一篇指引。 二、Nacos配置中心是如何引入SpringCloud项目中的呢&…

操作系统实验8:proc文件的实现

实验目的 掌握虚拟文件系统的实现原理实践文件、目录、索引节点等概念 实验内容 在Linux 0.11上实现procfs&#xff08;proc文件系统&#xff09;内的psinfo结点。当读取此结点的内容时&#xff0c;可得到系统当前所有进程的状态信息。例如&#xff0c;用cat命令显示/proc/p…

有限状态机

文章目录1.概念2.什么是计算3.什么是有限状态机3.1特性3.2为什么要用状态机4.实战4.1字符串转换整数4.2用有限状态机实现4.3源码1.概念 有限状态机&#xff08;英语&#xff1a;finite-state machine&#xff0c;缩写&#xff1a;FSM&#xff09;又称有限状态自动机&#xff0…

【手写 Vue2.x 源码】第十篇 - 数组数据变化的观测情况

一&#xff0c;前言 上篇&#xff0c;主要介绍了对象数据变化的观测情况&#xff0c;涉及以下几个点&#xff1a; 实现了对象老属性值变更为对象、数组时的深层观测处理&#xff1b; 结合实现原理&#xff0c;说明了对象新增属性不能被观测的原因&#xff0c;及如何实现数据…

综合案例二 旅游网【1.项目导入技术选型注册表单校验登录退出表单】注册表空指针异常和其他一些错误

目录 前提&#xff1a;项目导入 在maven中点击travel项目&#xff08;这里我是将项目添加到hello_maven里 &#xff09; 1.启动项目 方式一&#xff1a;maven命令启动 方式二&#xff1a;配置maven快捷启动 2.技术选型 1 Web层 2 Service层 3 Dao层 3.创建数据库…

56/14 shell脚本 后台启动 程序1 + “tail -f log“, ctrl +c 导致程序1中断

前言 接上一篇文章, node 程序后台执行加上 tail 命令, 中断 tail 命令, 同时也中断了 node 程序 我们来详细 参照对比一下 这个问题的各种情况 主要的脚本如下类似, 第一条命令 后台启动 程序1, 然后 第二条命令 tail -f 查看日志 然后 ctrlc 中断 "tail -f" …

实现自己的打印函数

文章目录前言前置知识代码说明实验操作单字符打印字符串打印整形字符串打印前言 本博客记录《操作系统真象还原》第六章实验的操作~ 实验环境&#xff1a;ubuntu18.04VMware &#xff0c; Bochs下载安装 实验内容&#xff1a; 实现 put_char 单字符打印输出函数。实现 put_…

TEE 背景知识

TEE 背景 计算机世界的安全&#xff0c;是保护计算机系统和网络免受攻击者的攻击&#xff0c;这些攻击可能导致未经授权的信息泄露、窃取或损坏硬件、软件或数据&#xff0c;以及它们所提供的服务的中断或误导。更多参考 Computer_security 1 安全是什么 谈安全&#xff0c;…

28.0:Combit LIST LABEL Reporting for Delphi Crack

作为 Delphi 开发人员的优势&#xff1a; 将 VCL 组件直接集成到 Embarcadero IDE 中 免版税报表设计器 交互式预览等 使用综合报表对象 Delphi 和所有其他相关语言和开发环境的报告工具。 将列表和标签集成到 Embarcadero RAD Studio List & Label 的 VCL 组件编译并直接…

HTML与CSS基础(八)—— CSS布局(定位、装饰、选择器拓展)

目标能够说出 定位 的常见应用场景 能够说出 不同定位方式 的特点 能够使用 子绝父相 完成元素水平垂直案例 能够写出三种常见的 光标类型&#xff08;cursor&#xff09; 能够使用 圆角边框 属性完成 正圆 和 胶囊按钮 效果 能够说出 display 和 visibility 让 元素本身隐藏 的…

【java查漏补缺】File类的使用

File类可以用来处理文件数据&#xff0c;比如使用list()方法可以获得某个文件夹下面的所有文件名。 File类的list()方法有一个含有一个参数的重载&#xff0c;在调用该方法的时候需要传入一个FilenameFilter对象&#xff0c;这样便可以进行文件名过滤。 我们先来看一下list()…

GJB 5000B二级-PP项目策划

一、主要变化情况 合并10项(绿色)、修订3项(蓝色)、删除1项(红色) 新增的主要内容 基于A版标准“项目策划”、“集成项目管理”、“定量项目管理”三个过程域中有关项目策划实践的内容来识别,没有新增实践,只增加了以下两个要求: 1、增加软件项目和设备/系统生存周…

Java线程之中断方法

interrupt()方法介绍interrupt() 给目标线程发送一个中断信号&#xff0c;同时将目标线程的中断标志设置为true。至于目标线程是否做出响应&#xff0c;需要看目标线程是否有对应的中断业务逻辑。场景1&#xff1a;假设&#xff0c;你是一个工厂的老板&#xff08;main线程&…

C++类和对象(下)

目录 初始化列表 explicit关键字 Static成员 友元 友元函数 友元类 匿名对象 内部类 初始化列表 初始化列表是以冒号开始&#xff0c;以逗号分割的成员列表&#xff0c;每一个成员变量后面跟一个放在括号中的初始值或表达式。&#xff08;代码演示以日期类为例&#xff…

【实现QQ登录界面 Objective-C语言】

一、实现QQ登录界面 1.实现这样的QQ登录界面 1.实现这样的QQ登录界面 2.首先,分析一下,这个界面里,都有哪些控件 是不是两个Label,两个TextField文本框,1个Button吧 3.先拖1个Label上来 再拖1个TextField文本框上来,在这个Label右边, 然后选中这两个控件, 按住o…

Altium Designer 超详细学习教程——印制电路板基础知识

在介绍Altium Designer软件使用办法之前先介绍下印制电路板的基础知识&#xff0c;不管是画图还是绘制PCB最终目的都是为了制作电路板&#xff0c;因此了解PCB的基础知识很有必要。 1.1印制电路板概述 1.1.1印制电路板结构 在进行PCB设计时&#xff0c;需要先对印制电路板的…