【JAVA】高效学习数据结构之二叉树基础篇(七千字超详细教程)

把温柔和例外留给值得的人:比如你

在这里插入图片描述
大家好,这里是新一,请多关照🙈🙉🙊。在本篇博客中,新一将会为大家介绍数据结构与算法之二叉树基础篇,我们知道二叉树在面试的时候出现频率是极高的,所以搞懂二叉树也成了学好数据结构的必经之路,所以为了方便大家理解,新一特地给大家附上了 源码和图片 便于大家理解,干货满满哟。(以下结果均在IDEA中编译)希望在方便自己复习的同时也能帮助到大家。😜😜😜🎪🚀🧰

以下是我们的文章



一.🎪 树的基本结构

树是一种非线性的数据结构操作,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的

1.1 🚀 树的特点

在这里插入图片描述
树具有以下特点:
● 有一个特殊的结点,称为根结点,根结点没有前驱结点。
● 除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、…、Tm,其中每一个集合Ti (1 <= i <=m) 又是一棵与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继。
● 树是 递归 定义的。
● 树形结构中,子树之间不能有交集, 否则就不是树形结构
在这里插入图片描述
那么树与非树的区别呢?
在这里插入图片描述

1.2 🚀 树的要素

在这里插入图片描述

二叉树概念解释
节点的度一个结点含有子树的个数称为该结点的度; 如上图:A的度为6
树的度一棵树中,所有结点度的最大值称为树的度; 如上图:树的度为6
叶子结点或终端结点度为0的结点称为叶结点; 如上图:B、C、H、I...等节点为叶结点
双亲结点或父结点若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B的父结点
孩子结点或子结点一个结点含有的子树的根结点称为该结点的子结点; 如上图:B是A的孩子结点
根结点一棵树中,没有双亲结点的结点;如上图:A
结点的层次从根开始定义起,根为第1层,根的子结点为第2层,以此类推
树的高度或深度树中结点的最大层次; 如上图:树的高度为4
非终端结点或分支结点具有相同父结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点
堂兄弟结点双亲在同一层的结点互为堂兄弟;如上图:H、I互为兄弟结点
结点的祖先从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先
子孙以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙
森林由m(m>=0)棵互不相交的树组成的集合称为森林

1.3 🚀 树的表现形式

树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,实际中树有很多种表示方式,如:双亲表示法,孩子表示法、孩子双亲表示法、孩子兄弟表示法等等。新一这里给大家介绍孩子兄弟表示法。
在这里插入图片描述

class BTNode3 {
    private char val;//数据域
    private BTNode3 firstChild;//第一个孩子节点
    private BTNode3 nextBrother;//从该节点往右第一个兄弟节点
}

听不懂?没关系,那下面这个还扛得住吗?🏀🏀🏀

在这里插入图片描述

1.4 🚀 树的应用

其实在不知不觉之间树已经深入我们的生活,就比如我们的任务管理器即是一种树形结构:
在这里插入图片描述

二.🎪 二叉树

一棵二叉树是结点的一个有限集合,该集合:要么为空,要么是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。

2.1 🚀 二叉树的特点

在这里插入图片描述

二叉树结构:
1.不存在度大于2的结点
2.它的子树有左右之分,次序不能颠倒,因此二叉树是有序树

在这里插入图片描述
在这里插入图片描述
二叉树有以下几种形态:
在这里插入图片描述
注意:即便它是空树或者只有根,它也是二叉树

2.2 🚀 满二叉树与完全二叉树

这两种二叉树非常重要,不管是在做题还是在面试中。

满二叉树

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

完全二叉树

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

在这里插入图片描述

2.3 🚀 二叉树的性质*

以下性质非常重要,请友友们牢记:

1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有 2^(i-1)个结点
在这里插入图片描述

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

当深度为K的二叉树最大节点数即为全部放满——满二叉树,把各层最大数相加即可,等比数列求和:2^0 + 2^1 + 2^2 + ...... + 2^(k-1) = 2^k - 1

3. 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1
在这里插入图片描述
对于任意一颗二叉树我们知道它的节点总数 n = n0 + n1 + n2,而它的总边数为n - 1,因为相当于一个子节点一条边,根节点没有边,一个度为2的父节点产生2条边,度为1的父节点产生一条边,叶子节点作为父节点时不产生边,故我们得到以下式子:
n = n0 + n1 + n2
n - 1 = 0 * n0 + 1 * n1 + 2 * n2

两式结合即可以得到 n0=n2+1

5. 具有n个结点的完全二叉树的深度klog2(n + 1)(以2为底的对数)上取整

先拿一颗满二叉树来举例:我们知道对于它有 2 ^ k - 1 = n,由此可得k = log2(n + 1)

在这里插入图片描述

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

🧰练习

在这里插入图片描述
答案:1.B 2.A 3.B 4.B

相信不少小伙伴对第二题有所疑惑吧,不慌我们来看看这棵完全二叉树
在这里插入图片描述
我们发现对于任何一棵完全二叉树来说:

偶数个节点: n1 = 1
奇数个节点: n1 = 0

故第二题:2n = n0 + n1 + n2 = n0 + 1 + n0 - 1 = 2 * n0 = 2n

2.4 🚀 二叉树的存储

二叉树的存储结构分为:顺序存储和类似于链表的链式存储,这里新一先给大家介绍链式存储

二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有孩子表示法和孩子双亲表示法表示方式,具体如下:

在这里插入图片描述

class BTNode1{
    int val;
    private BTNode1 left;//左孩子引用
    private BTNode1 right;//右孩子引用
    //做题以及面试常考
}
class BTNode2{
    int val;
    private BTNode2 left;//左孩子引用
    private BTNode2 right;//右孩子引用
    private BTNode2 parent;//双亲 - 该节点的根节点
    //AVL + 红黑 + B树会用
}

下面我们二叉树的遍历主要用的是孩子表示法

三.🎪 二叉树的遍历

二叉树的遍历十分重要,可以说大部分二叉树的题都要通过二叉树的遍历从而解答,二叉树的遍历一共有四种:前序遍历,中序遍历,后序遍历,层序遍历

3.1 🚀 前序遍历

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

在这里插入图片描述
中序遍历跟后序遍历跟前序遍历那里类似,不过要记住:无论是那种遍历,所有二叉树的子二叉树都要遵循其原则,二叉树的遍历是要通过递归来实现的,见下:

在这里插入图片描述

//前序遍历
    void preOrder(TreeNode root) {//传入二叉树的根
        if (root == null){//判断根是否为空
            return;
        }
        System.out.print(root.val + " ");//打印节点信息
        preOrder(root.left);//递归遍历该根节点的左子树
        preOrder(root.right);//递归遍历该根节点的右子树
    }

前序遍历结果:1 2 3 4 5 6

3.2 🚀 中序遍历

中序遍历:根的左子树—>根节点—>根的右子树。

在这里插入图片描述

//中序遍历
    void inOrder(TreeNode root){//传入二叉树的根
        if (root == null){//判断根是否为空
            return;
        }
        inOrder(root.left);//递归遍历该根节点的左子树
        System.out.print(root.val + " ");//中序打印根节点
        inOrder(root.right);//递归遍历该根节点的右子树
    }

中序遍历结果:3 2 1 5 4 6

3.3 🚀 后序遍历

后序遍历:根的左子树—>根的右子树—>根节点。
在这里插入图片描述

void postOrder(TreeNode root){//传入二叉树的根
        if (root == null){//判断根是否为空
            return;
        }
        postOrder(root.left);//递归遍历该根节点的左子树
        postOrder(root.right);//递归遍历该根节点的右子树
        System.out.print(root.val + " ");//后序打印根节点
    }

后序遍历结果:3 1 5 6 4 1

3.4 🚀 层序遍历

层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

在这里插入图片描述
🧰练习
在这里插入图片描述
答案:1.A 2.A 3.D 4.A

总结下来这几道题就一个思路:先根据前序遍历或者后序遍历找到根,在通过这个根在中序遍历中找到其左子树和右子树,再通过前序或者后序找到子树的根,如此循环即可画出对应的二叉树

值得注意的是:只知道前序和后续遍历无法唯一确定二叉树,除此之外,知道这三个其中任意两个即可知道唯一确定的二叉树

💕家人们,学到这里我们的数据结构与算法中的e二叉树基础已经彻底弄懂啦,但这只是二叉树结构中很基础的一部分,后续新一还会继续更新二叉树有关内容,包括创建二叉树等方法的实现以及典型例题,如果觉得新一讲得还清楚的话,可以点个赞支持一下哦🥳🥳🥳后续新一会持续更新JAVA的有关内容,学习永无止境,技术宅,拯救世界!
在这里插入图片描述

评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Corwttaml

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值