二叉树讲解

news2024/12/23 13:14:10

对于二叉树,是真正的很难!很难,不是一般的难度!!

笔者学习完二叉树,笔记记录了得有三十多页,但是,还是很不理解(做题不怎么会)

下面进入二叉树的基础部分:

二叉树概念!!

一颗二叉树是节点的一个有限集合:该集合

  1. 或者为空

  1. 或者是由一个根节点加上两颗别称为左子树和右子树的二叉树组成

经过上述,我们可以得出:

  1. 二叉树不存在度大于2的节点(对于度是什么,不理解的读者,可以参考笔者的之前的文章:https://blog.csdn.net/weixin_64308540/article/details/129045341

  1. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树(左右顺序)

经过二叉树的上述内容的讲解,我们可以得出:对于任意类型的二叉树,都是由一下的几种情况复合而成的!

经过上述的内容,我们便可以根据自己的想法,设计任意类型的二叉树了!!

下面我们来进行讲解一下两种特殊的二叉树:

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

对于这个满二叉树,我们可以根据层数,每层的个数,最后得出节点的个数(考试可能会考)

  1. 完全二叉树: 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

在这里,我们需要注意的是:满二叉树是一种特殊的完全二叉树

二叉树的性质!!

  1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有 (i>0)个结点

  1. 若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是 (k>=0)

  1. 具有n个结点的完全二叉树的深度k为 上取整

  1. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i 的结点有: 1.若i>0,双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点 2.若2i+1<n,左孩子序号:2i+1,否则无左孩子 3.若2i+2<n,右孩子序号:2i+2,否则无右孩子

  1. 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1

对于第5点,笔者在后续的代码/选择题/解答题当中,经常使用!所以,我们需要知道它的推理由来!!(笔者由一颗完全二叉树为列,来进行讲解)

根据上述的二叉树的性质,来做几个简单的练习题吧!!
  1. . 某二叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该二叉树中的叶子结点数为( 200) 提示:叶子节点为:度为0的节点(不知道度是什么的,可以参考:https://blog.csdn.net/weixin_64308540/article/details/129045341)

  1. 在具有 2n 个结点的完全二叉树中,叶子结点个数为( n)

提示:2n是个偶数!!

思考一下:当奇数节点的时候,又会是怎么个结果??思路跟刚才的一样!感兴趣的可以自己思考一下!

  1. 一个具有767个节点的完全二叉树,其叶子节点个数为(384) 首先我们需要根据767(奇数),完全二叉树来进行思考!

  1. 一棵完全二叉树的节点数为531个,那么这棵树的高度为( 10

这个便不再解析了,大家自行解决!答案已经给出

二叉树的存储

二叉树的存储结构分为:顺序存储和类似于链表的链式存储。 二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式,

表示方式:

  1. 孩子表示法(比较常见)

class Node{
    int val;//数据域
    Node left;//左孩子的引用,常常代表左孩子为根的整根左子树
    Node right;//右孩子的引用,常常代表右孩子为根的整根右子树
}
  1. 孩子双亲表示法(后续平衡树时候,会用到)

class Node{
    int val;//数据域
    Node left;//左孩子的引用,常常代表左孩子为根的整根左子树
    Node right;//右孩子的引用,常常代表右孩子为根的整根右子树
    Node parent;//当前节点的根节点
}

学习了这么多!!有没有兴趣跟着笔者来手动创建一颗二叉树呢??(不容拒绝哟!)

手动创建一颗二叉树吧!!
public class TestBinaryTree {
    static class TreeNode{
        public char val;//数据域
        public TreeNode left;//左孩子的引用
        public TreeNode right;//右孩子的引用

        public TreeNode(char val) {
            this.val = val;
        }
    }
    
    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;
        A.right=C;
        B.left=D;
        B.right=E;
        C.left=F;
        C.right=G;
        E.right=H;
        
        return A;//A是跟节点
    }

    public static void main(String[] args) {
        TestBinaryTree testBinaryTree=new TestBinaryTree();
        TestBinaryTree.TreeNode root=testBinaryTree.createTree();
        System.out.println("成功的创建出来了一个二叉树!");
    }
}

根据上述的代码,我们在刚刚实列化节点的时候:

在最后,我们所创建的二叉树模型为:

在这个代码中:当出了createTree方法之后,所创建的A,B,C,D,E,F,G,H,都会被回收掉了,但是创建好的A节点已经被return ,其所对应的关系不会被回收!!

二叉树的遍历

其实二叉树的遍历方式有前序遍历,中序遍历,后序遍历,还有层序遍历!!这些要求我们都得掌握!!加油!

从二叉树的递归定义可知:一颗非空的二叉树,由根节点及其左子树,右子树这三个部分组成的,因此,在任一给定节点上,可以按照某种次序执行三个操作:

  1. 访问节点本身(N)

  1. 遍历该节点的左子树(L)

  1. 遍历该节点的右子树(R)

根据以上的思考,对于上述三种操作,我们可以有:NLR,LNR,LRN;NRL,RNL,RLN这六种操作,但是,需要注意的是:前面三种次序与后面三种次序相对称,故,我们只考虑前面的三种就可以了!!

遍历命名

根据访问节点操作发生的位置来命名!!

  1. NLR:前序遍历!访问根节点的操作发生在遍历其左右子树之前(根左右)

  1. LNR:中序遍历!访问根节点的操作发生在遍历其左右子树之间(左根右)

  1. LRN:后序遍历!访问根节点的操作发生在遍历其左右子树之后(左右根)

对于前序遍历,中序遍历,后序遍历,的深层操作:

  1. 前序遍历(根左右):若二叉树非空,则依次执行如下操作:1。访问根节点,2。遍历左子树,3.遍历右子树

  1. 中序遍历(左根右):若二叉树非空,则依次执行如下操作:1。遍历左子树,2。访问根节点,3.遍历右子树

  1. 后序遍历(左右根):若二叉树非空,则依次执行如下操作:1。遍历左子树,2。遍历右子树,3.访问根节点

层序遍历!

所谓的层序遍历就是从所在二叉树的根节点出发,首先访问第1层的树根节点,然后从左到右访问第2层的节点,接着是第3层的节点,以此类推,自上而下,自左到右,逐层访问树的节点的过程,就是层序遍历!

根据前序遍历,中序遍历,后序遍历,层序遍历,来做几个小题吧!!
  1. 写出该二叉树的前序,中序,后序的遍历结果:

  1. 前序遍历:ABDEHCFG;

  1. 中序遍历:  DBEHAFCG;

  1. 后序遍历:  DHEBFGCA;

  1. 层序遍历:   ABCDEFGH;

  1. 某完全二叉树按层次输出(同一层从左到右)的序列为 ABCDEFGH 。该完全二叉树的前序序列为(ABDFECFG) 根据层序遍历写出原始的二叉树即可!

  1. 二叉树的前序遍历和中序遍历如下:先序遍历:EFHIGJK;中序遍历:HFIEJKG.则二叉树根结点为(E)

前序遍历的第一个节点就是根节点!!

中序遍历找到根的位置,左边就是左子树,右边就是右子树!!然后我们根据题意可以画出该二叉树!

  1. .设一课二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列为(abcde)

根据题意,我们可以得出,二叉树为:

  1. .某二叉树的后序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同一层从左到右)的序列为(FEDCBA)

根据题意,我们可以得出,二叉树为:

经过了上述题目的洗涤,想必此时的你,已经对二叉树的前序遍历,中序遍历,后序遍历,层序遍历已经有着自己的思路了吧!!那么,接下来,我们便可以进入代码环节了!!

递归(前中后遍历)

前序遍历(根左右)递归
    //二叉树的前序遍历(递归)
    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;
        }
        preOrder(root.left);//左
        System.out.print(root.val+" ");//根
        preOrder(root.right);//右
    }
后序遍历(左右根)递归
 //二叉树的后序遍历(递归)
    public void postOrder(TreeNode root){
        if (root==null){
            return;
        }
        preOrder(root.left);//左
        preOrder(root.right);//右
        System.out.print(root.val+" ");//根
    }

二叉树的基本操作

对于二叉树的基本操作有很多!希望尽可能多的去全面理解,消耗!

    // 获取树中节点的个数
    int size(Node root);
    // 获取叶子节点的个数
    int getLeafNodeCount(Node root);
    // 子问题思路-求叶子结点个数
    
   // 获取第K层节点的个数
    int getKLevelNodeCount(Node root,int k);
    // 获取二叉树的高度
    int getHeight(Node root);
    // 检测值为value的元素是否存在
    Node find(Node root, int val);
    //层序遍历
    void levelOrder(Node root);
    // 判断一棵树是不是完全二叉树
    boolean isCompleteTree(Node root);

下面便带领大家走进二叉树的基本操作环节!!更加深读!!

  1. 获取树中节点的个数(左节点+右节点+根节点)

方法1:

   //获取树中节点的个数(左节点+右节点+根节点)
    public int size(TreeNode root){
        if (root==null){
            return 0;
        }
        int leftSize=size(root.left);
        int rightSize=size(root.right);
        return leftSize+rightSize+1;
    }

方法2:

    public  int nodeSize;//成员变量

    public void size2(TreeNode root){
        if (root==null){
            return;
        }
        nodeSize++;//每遇到一个节点就++
        size2(root.left);
        size2(root.right);
    }
  1. 获取叶子节点的个数(子思路问题)

方法1:

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

方法2:

 public int leafSize;
    void getLeafNodeCount2(TreeNode root){
        if (root==null){
            return;
        }
        if (root.left==null && root.right==null){
            leafSize++;
        }
        getLeafNodeCount2(root.left);
        getLeafNodeCount2(root.right);
    }
  1. 获取第K层节点的个数

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

方法1:

   //获取二叉树的高度
    public int getHeight(TreeNode root){
        if (root == null) {
                return 0;
            }
        return (getHeight(root.left)>(getHeight(root.right))?(getHeight(root.left)+1 ): (getHeight(root.right)+1));
    }
    

方法2:

   public int getHeight2(TreeNode root){
        int leftHeight=getHeight2(root.left);//左数的高度
        int rightHeight=getHeight2(root.right);//右数的高度
        return (leftHeight>rightHeight)?(leftHeight+1):(rightHeight+1);
    }
  1. 检测值为value的元素是否在二叉树中

    //检测值为value的元素是否在二叉树中
    TreeNode find(TreeNode root,int val){
        if (root==null){
            return null;
        }
        if (root.val==val){
            return root;
        }
        //左子树找到
        TreeNode leftTree=find(root.left,val);
        if (leftTree!=null){
            return leftTree;
        }
        //右子树找到
        TreeNode rightTree=find(root.right,val);
        if (rightTree!=null){
            return rightTree;
        }
        //都没有找到
        return null;
    }
    

上述的二叉树的基本操作,笔者没有实现完成,主要原因还是在于:剩下没有写的那些操作,基本都是题目了!!所以,我们可以通过系统的练习,来加深印象!!

感兴趣的可以看一下笔者的后续二叉树文章!!

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

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

相关文章

无法决定博客主题的人必看!如何选择类型和推荐的 5 种选择

是否有人不能迈出第一步&#xff0c;因为博客的类型还没有决定&#xff1f;有些人在出发时应该行动&#xff0c;而不是思考&#xff0c;但让我们冷静下来&#xff0c;仔细想想。博客的难度因流派而异&#xff0c;这在很大程度上决定了随后的发展。因此&#xff0c;在选择博客流…

关于IDM下载器,提示:一个假冒的序列号被用来注册……idea项目文件路径报红

关于IDM下载器&#xff0c;提示&#xff1a;一个假冒的序列号被用来注册……到C:\Windows\System32\drivers\etc 修改目录下面的hosts文件&#xff08;如果没有修改的权限就右键属性hosts文件修改user的权限为完全控制&#xff09;&#xff0c;在hosts里面增加以下内容&#xf…

RadGraph: Extracting Clinical Entities and Relations from Radiology Reports代码

文章来源&#xff1a;NeurIPS 文章类别&#xff1a;IE(Information Extraction) RadGraph主要基于dygie&#xff0c;主要文件为inference.py。 inference.py&#xff1a; 1、get_file_list(data_path) def get_file_list(path):file_list [item for item in glob.glob(f&q…

遮挡贴图(Occlusion Map)和微表面贴图(Microsurface Map)

遮挡贴图&#xff08;Occlusion Map&#xff09; 在3D图形学中&#xff0c;遮挡&#xff08;Occlusion&#xff09;是指光被物体挡住。即便是在PBR中&#xff0c;环境光在某些应该被遮挡的地方&#xff0c;也会以古怪的方式被反射。遮挡贴图&#xff08;Occlusion Map&#xff…

ffmpeg h264文件转mp4

h264文件不能直接在网页上播放&#xff0c;比如在浏览器上输入http://10.0.0.2/2022-01-08T22-32-58.h264&#xff0c;变成了下载。 若在浏览器上输入http://10.0.0.2/2022-01-08T22-32-58.mp4&#xff0c;则可以播放。 本文讲解用ffmpeg将h264文件转换成mp4。 首先&#xf…

视频融合 flv流格式对接(上)

FLV 是FLASH VIDEO的简称&#xff0c;FLV流媒体格式是随着Flash MX的推出发展而来的视频格式。由于它形成的文件极小、加载速度极快&#xff0c;使得网络观看视频文件成为可能&#xff0c;它的出现有效地解决了视频文件导入Flash后&#xff0c;使导出的SWF文件体积庞大&#xf…

R-Drop: Regularized Dropout for Neural Networks 论文笔记(介绍,模型结构介绍、代码、拓展KL散度等知识)

目录前言一、摘要二、R-Drop介绍三、R-Drop公式详解四、R-Drop计算流程附录0&#xff1a;代码附录一&#xff1a;熵以及信息熵附录二&#xff1a;KL散度&#xff08;相对熵&#xff09;附录三&#xff1a;JS散度附录四&#xff1a;互信息总结前言 R-Drop——神经网络的正则化Dr…

必看!Salesforce管理员职场如何快速晋升?

2023年的开局略显艰难&#xff0c;在当前的经济环境下&#xff0c;许多行业仍面临挑战。虽然交易周期可能会变得更长&#xff0c;但对新的Salesforce实施仍有巨大需求&#xff0c;现有客户仍然需要经验丰富的专业人员来优化和维护他们的Salesforce组织。 在过去的三年中&#x…

大规模即时云渲染技术,追求体验与成本的最佳均衡

现实世界映射其中&#xff0c;传统文化沉浸其境&#xff0c;旧时记忆交互其间。 仲升&#xff5c;技术作者 IMMENSE&#xff5c;内容编辑 在刚刚过温的春节&#xff0c;云之上&#xff0c;带来了一场「数字文化」新体验。 游花车、舞狮子、踩高跷、放烟花、写福字……还记得儿…

2023最强软件测试面试题,精选100 道,内附答案版,冲刺金3银4

精挑细选&#xff0c;整理了100道软件测试面试题&#xff0c;都是非常常见的面试题&#xff0c;篇幅较长&#xff0c;所以只放出了题目&#xff0c;答案在评论区&#xff01; 测试技术面试题 1、什么是兼容性测试&#xff1f;兼容性测试侧重哪些方面&#xff1f; 2、我现在有…

css复习3

精灵图的使用 为了有效地减少服务器接收和发送请求的次数&#xff0c;提高页面的加载速度&#xff0c;出现了 CSS 精灵技术&#xff08;也称 CSS Sprites、CSS 雪碧&#xff09;。 核心原理&#xff1a;将网页中的一些小背景图像整合到一张大图中 &#xff0c;这样服务器只需要…

新S/MIME标准将于今年九月生效

1月份&#xff0c;行业领导者通过了新的 S/MIME基线要求&#xff0c;旨在规范全球范围内公开信任电子邮件签名证书的颁发和管理。以下是关于此次更新的重点……根据abnormal security发布的报告称&#xff0c;近92%的受访者表示&#xff0c;他们在过去一年中至少经历过一次或多…

全网最全的Ansible中常用模块讲解

目录 前言 一、ansible实现管理的方式 二、Ad-Hoc执行方式中如何获得帮助 三、ansible命令运行方式及常用参数 四、ansible的基本颜色代表信 五、ansible中的常用模块 1、command 2、shell 3、script 4、copy 5、fetch 6、file 7、 unarchive 8、archive 9、h…

Python基础1

1. 注释 单行注释&#xff1a;以#开头。一般建议注释和内容用空格隔开。 多行注释&#xff1a;以一对三个双引号括起来的内容是注释。“““示例注释”””。 2. 数据类型 验证数据类型的方法&#xff1a;type&#xff08;被查看类型的数据&#xff09;。 注意&#xff1a;…

< 每日小技巧:N个很棒的 Vue 开发技巧, 持续记录ing >

每日小技巧&#xff1a;6 个很棒的 Vue 开发技巧&#x1f449; ① Watch 妙用> watch的高级使用> 一个监听器触发多个方法> watch 监听多个变量&#x1f449; ② 自定义事件 $emit() 和 事件参数 $event&#x1f449; ③ 监听组件生命周期常规写法hook写法&#x1f44…

扫码过磅+车牌识别,内蒙古蒙维过磅实现信息化管理

扫码过磅、车牌识别、对接SAP ERP系统设计思路&#xff1a; 无人值守系统升级改造包括车牌自动识别系统、信息化&#xff08;扫码等方式&#xff09;管理系统、智能自动控制系统等实现信息无纸化传递。远程监管地点设于公司东磅房&#xff0c;可以实现远程监测监控画面、称重过…

前端之HTML

一、概念1.页面组成结构&#xff1a;HTML&#xff08;Hyper Text Markup Language--超文本标记语言&#xff09;页面原始和内容 表现&#xff1a;CSS网页原始的外观和位置等页面样式&#xff08;如颜色、大小等&#xff09; 行为&#xff1a;JavaScript网页模型的定义与交互&am…

【仓库管理】搭建 Maven 私服之一--Nexus仓库(Repository)管理软件

文章目录Nexus是什么Nexus下载和安装1. 进入 Nexus 2.x 下载页面&#xff0c;根据本机操作系统&#xff0c;选择对应的版本进行下载&#xff0c;如下图所示。2. 将下载 Nexus 安装包解压到本地磁盘&#xff0c;可获得 nexus-2.14.20-02 和 sonatype-work 2 个目录&#xff0c;如…

Python3,2分钟掌握Doscoart库,你也能成为艺术家。

2行代码绘制水彩画1、引言2、 代码实战2.1 模块介绍2.2 模块安装2.3 代码示例2.3.1 创建默认图片2.3.2 设置参数创建图片2.3.3 查看设置参数2.3.4 查看配置2.3.5 保存配置2.3.6 加载配置2.3.7 导出配置文件2.3.7 生成Python代码2.3.8 调用文档3、总结1、引言 小屌丝&#xff1…

分布式新闻项目实战 - 11.定时计算热点文章(xxl-Job)

男人过了四十&#xff0c;千万要少说话&#xff0c;拉长脸&#xff0c;闭紧嘴&#xff0c;买件立领风衣&#xff0c;浓个眉大个眼&#xff0c;一直走&#xff0c;不要往两边看&#xff0c;还能再混几十年。 —— 冯唐 系列文章目录 项目搭建App登录及网关App文章自媒体平台&am…