数据结构:二叉树、二叉查找树、红黑树、B树以及B+树一锅端

一、树

树(Tree)是一种抽象数据类型,用来模拟具有树状结构性质的数据集合,它是n(n>=0)个节点的有限集,通过连接他们的边组成一个具有层次关系的集合,它看起来像一棵倒挂的树,也就是说它是根朝上,叶子朝下。在任意一棵非空树中应该满足:
(1)有且仅有一个特定的称为根的节点;
(2)当n>1的时候,其余节点可以分为m(m>0)个互不相交的有限集合T1,T2…Tm,其中每个集合本身又是一棵树,并且称为根的子树。树的定义是递归的,树的定义中又用到了其自身,树是一种递归的数据结构。树具有如下特点:

  • 树根节点没有前驱,除了根节点之外的所有节点有且只有一个前驱。
  • 树的所有节点有零或者多个后继。
    树适合表示具有层次结构的数据,树中的某个节点最多只和上一层的一个节点有直接关系,根结点没有直接上层节点,因此在n个节点的树中有n-1条边。树中每个节点和其下一层的0或者多个节点有直接关系。
    在这里插入图片描述

(3)根节点A到根结点D的唯一路径上的任意节点,称为节点D的祖先。如节点A是节点D的祖先,节点D是节点A的子孙。路径上最接近D的节点称为D的双亲,而D是节点B的孩子。根结点A是树中唯一没有双亲的节点。有相同双亲的节点称为兄弟,如D节点和E节点有相同的双亲B,即D是E的兄弟。
(4)树中一个节点的孩子的个数称为该节点的度,树中节点的最大度数称为树的度。如节点B的度是2,节点C的度是3,树的度是3.
(5)度大于0的节点称为分支节点(非终端节点);度为0的节点(没有子女的节点)称为叶子结点(终端节点),在分支节点中,每个分支数就是该节点的度。
(6)节点的深度、高度和层次。节点的层次是从树根开始定义的,根结点是第一层,字节点是第二层,以此类推;节点的深度是从根节点自顶向下开始逐层累加的;节点高度是从叶子结点自底向上逐层累加的。树的高度或者深度是树中节点的最大层数,如上图这棵树的高度(深度)是3。
(7)有序树和无序树。树中节点的各个子树从左到右是有次序的,不能交换,这是有序树,否则称为无序树。
(8)路径和长度:树中两个节点之间的路径是由两个节点之间所经过的节点序列构成的,而路径长度是路径上所经过的边的个数。
(9)森林。森林是m棵互不相交的树的集合。森林和树的概念十分相似,因为只要把树的根节点删去就称为了森林,反之只要给m棵独立的树加上一个节点,并把这m棵树作为该节点的子树,则森林就变成了树。
(10)树的节点树等于所有的节点的度加1;度为m的树中,第i层至多有m的i-1次方个节点;

树的种类有很多,像上面的一个节点有多余两个节点的树,称为多路树,而每个节点最多只能有两个子节点的树称为二叉树。节点:如上图中的圆圈,比如A,B,C等表示节点,节点一般代表一些实体,在Java编程中,节点一般代表对象;边:连接节点的线称为边,边表示节点的关联关系,一般从一个节点到另外一个节点的唯一方法就是沿着一条有边的道路前进。

二、二叉树

二叉树是另一种树形结构,特点是每个节点最多只有两棵树(即二叉树不存在度大于2的节点),并且二叉树的子树有左右之分,次序不能任意颠倒。
(1)与树类似,二叉树也是递归的形式定义,二叉树是n个节点的有限结合:

  • 或者为空二叉树,即n=0;
  • 或者由一个根结点和两个互不相交的被称为根的左子树和右子树组成。左子树和右子树分别是一棵二叉树。

(2)二叉树是有序树,如果将其左子树和右子树颠倒,则会成为另外一棵不同的二叉树。即使树中只有一棵子树,也是要区分它是左子树还是右子树。

(3)度为2的树和二叉树的区别:

  • 度为2的树至少有三个节点,而二叉树可以为空;
  • 度为2的有序树的孩子的左右次序是相对于另一个孩子而言的,若某个节点只有一个孩子,则这个孩子就无须区分其左右次序;而二叉树无论其孩子数是否为2,均需要确定其左右次序,即二叉树的节点次序不是相对于另一个节点而言的,而是确定的。

(3)特殊的二叉树

  • 满二叉树。一棵高度为h,且有2^h-1个节点的二叉树称为满二叉树,即树中的每层都有最多的节点,满二叉树的叶子结点都在二叉树的最下面一层,并且除了叶子结点之外的每个节点的度都是2;完全二叉树,高度为h、有n个节点的二叉树,当且仅当每个节点都与高度为h的满二叉树中的编号为1~n节点一一对应时称为完全二叉树;二叉排序树(二叉搜索树),左子树上的所有节点的关键字均小于根结点的关键字,右子树上的所有节点关键字均大于根节点的关键字,左子树和右子树又各是一棵二叉排序树;平衡二叉树,树上的任意节点的左子树和右子树的深度差不超过1。如下图满二叉树和完全二叉树:
    在这里插入图片描述
    (4)二叉树的存储结构
    二叉树的顺序存储是用一组地址连续的存储单元依次自上而下,自左至右存储完全二叉树上的节点元素,即将完全二叉树上编号为i的节点元素存储在一维数组下标为i-1的分量中。完全二叉树和满二叉树采用顺序存储比较合适,树中的节点序号可以唯一地反映节点之间的逻辑关系,这样既能最大可能的节省存储空间,又能利用数组元素的下标值确定节点再二叉树中的位置,以及节点之间的关系。对于一般二叉树,为了让数组下标能反映二叉树中节点之间的逻辑关系,只能添加一下并不存在的空节点,让其每个节点与完全二叉树上的节点对照,再存储到一维数组的相应分量中,所以此时链式存储的空间利用率比较低,因此二叉树一般都采用链式存储,用链式存储二叉树中的每个节点,在二叉树中,节点结构通常包含若干数据却与和若干指针区域,二叉链表至少包含三个区域:数据域data、左指针lchild和右指针rchild。
    在这里插入图片描述
    常用的二叉链表的存储结构如下,二叉链表还增加了指针域
    在这里插入图片描述

三、二叉搜索树(二叉排序树、二叉查找树Binary Search Tree,BST)

3.1 二叉搜索树介绍

二叉排序树定义:

  • 二叉排序树或者是一棵空树,或者是具有如下特性二叉树:
    若它的左子树不为空,则左子树上的所有节点的值都小于根节点的值;若它的右子树不为空,则右子树上所有的节点的值均大于它的根节点的值;它的左、右树叶分别为二叉排序(二叉搜索树)树。

在这里插入图片描述
(1)二叉搜索树查找节点
查找某个节点,我们必须从根节点开始查找。查找的值比当前节点的值大,则搜索右子树;查找的值等于当前节点的值,则停止搜素(终止条件);查找值小于当前节点的值,则搜索左子树。
(2)二叉搜索树插入节点
要插入节点,必须先找到要插入的位置,与查找操作类似,由于二叉搜索树的特性,待插入的节点也需要从根节点开始进行比较,小于根节点则和根节点的左子树进行比较,反之则和根节点右子树进行比较,知道左子树为空或者右子树为空,则插入到相应为空的位置。
(3)二叉搜索树遍历节点
遍历树是根据一种特定的顺序访问树的每一个节点,比较常用的三种遍历方式分别是:前序遍历、中序遍历和后序遍历,而二叉搜索树最常用的就是中序遍历。

  • 中序遍历:左子树—>根节点—>右子树
  • 前序遍历:根节点—>左子树—>右子树
  • 后续遍历:左子树—>右子树—>根节点
    对于上面这棵二叉树,前序遍历结果为:10->8->4->5->9->15->11->20;中序遍历结果为:4->5->8->9->11->15->20->10;后序遍历的结果为:5->4->9->8->11->20->15->10

(4)二叉搜索树查找最大值和最小值
要找最小值,先要查找根节点,然后一直查找左节点的左节点,如果这个节点没有左节点,那么这个节点就是最小值。同理要找最大值,一直找根节点的右节点,直到没有右节点,则就是最大值。

(5)二叉搜索树删除节点
删除节点是二叉搜索树中最复杂的操作,删除节点有三种情况。

  • 该节点是叶子结点(没有子节点)
    要删除叶子节点,只需要改变该节点的父节点引用该节点的值,即可将其引用改为null即可。
    在这里插入图片描述
  • 该节点有一个子节点
    删除有一个子节点的节点,我们只需要将其父节点原本节点指向该节点的引用,改为指向该节点的子节点即可
    在这里插入图片描述
  • 该节点有两个子节点
    当删除的节点有两个子节点,那么删除之后,两个子节点的位置我们就没有办法处理了。既然处理不了,我们就用中序遍历的后继节点来填充,用后继节点来代替被删除的节点,显然该二叉搜索树还是有序的。
    在这里插入图片描述
    (6)删除没有子节点的节点
    这种节点直接删除即可

3.2 二叉搜索树时间复杂度分析

二叉查找树的查找效率主要取决于树的高度。若二叉查找树的左、右子树的高度差的绝对值不超过1,则这样的二叉查找树称之为平衡二叉树,平均查找的时间复杂度为O(log2n)。若数据值单调递增或者单调递减的话,即二叉排序树是一个只有左子树或者右子树的话(类似于单链表),则其平均查找的时间复杂度为O(n)。最坏情况下的二叉排序树的输入序列是有序的,会形成一个倾斜的单支树,此时二叉排序树的性能显著变坏,树的高度为元素的个数n。

四、平衡二叉树

为了解决上面的有序数据形成的单支树的问题,以及避免树的高度增长过快的问题降低二叉排序树的性能,我们引入了平衡二叉树。平衡二叉树规定在插入和删除二叉树节点的时候,要保证左、右树的高度差的绝对值不超过1,这样的树称之为平衡二叉树。平衡二叉树的定义如下:

  • 平衡二叉树可以是一棵空树;
  • 左子树和右子树都是一棵平衡二叉树,左子树和右子树的高度差不超过1,插入之后如果造成了某个节点不平衡则需要作出相应的调整,包括LL平衡旋转、RR平衡旋转、LR平衡旋转、RL平衡旋转。
  • LL平衡旋转(右单旋转)。由于在在节点A的左孩子(L)的左子树(L)上插入新节点,A的平衡因子由1增加到2,导致以A为根的子树失去平衡,需要向右旋转一次。将A的左孩子B向右上旋转代替A成为根节点,将A节点向右下旋转成为B的右子树的根节点,而B的柚子树则作为A节点的左子树。如下图所示:
    在这里插入图片描述
  • RR平衡旋转(左单旋转)。由于在A节点的右孩子的右子树上插入了新节点,A的平衡因子从-1变成了-2,导致以A为根的子树失去了平衡,需要做一次向左的旋转。将A的右孩子B向左上旋转代替A,将A节点向左下旋转旋转成B的左子树的根节点,而B的原左子树则作为A节点的右子树,如下图所示:
    在这里插入图片描述
  • LR平衡旋转(先左后右)。由于A的左孩子的右子树上插入新节点,A的平衡因子由1增加到2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先左旋转后右旋转。先将A节点的左孩子B的右子树的根接待你C向左上方旋转提升到B节点的位置,然后再把C节点向右上旋转提升到A节点的位置。如下图所示:
    在这里插入图片描述
  • RL平衡旋转(先右后左)。由于在A的右孩子R的左子树L上插入新节点,A的平衡因子由-1变成-2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先右后左。先讲A的右孩子的左子树的根节点C向右上旋转提升到B节点的位置,然后再把该C节点向左上旋转提升到A节点的位置。如下图所示:
    在这里插入图片描述

五、红黑树(Red-Black Tree,简称RBT)

平衡二叉树可以保证不会出现大量的节点偏向一边的情况。但是平衡二叉树要求每个节点的左子树和右子树的高度差至多等于1,导致每次进行插入/删除节点的时候,几乎都会破坏平衡二叉树的规则,进而需要通过坐旋转和右旋转来进行调整,使之成为一棵符合要求的平衡二叉树。如果在插入、删除很频繁的场景中,平衡二叉树需要进行频繁的调整,这会使得平衡树性能大打折扣,为了解决这个问题引入了红黑树。红黑树是一棵自平衡的二叉查找树,给每个节点一个红色或者黑色,通过颜色来保证树基本上是平衡的,红黑树不像平衡二叉树那样要求那么严格,要求高度差不大于1,红黑树要求低一点,调整的频率没有平衡二叉树多,但是平衡性没有平衡二叉树好。如果插入和删除不是很频繁,但是搜索很频繁,这时候就用平衡二叉树;如果插入和删除很频繁,这时候应该用红黑树
在这里插入图片描述

5.1红黑树的性质

(0)红黑树是一棵很特殊的二叉查找树
(1)要求1:每个节点要么是黑色要么是红色
(2)要求2:根节点是黑色的
(3)要求3:每个叶子结点是黑色不存储数据的空节点
(4)要求4:每个红色节点的两个子节点一定都是黑色的,不能有两个红色节点相连,这是红属性。即任何相邻的两个父子结点不能同时为红色。但是l两个黑色的结点是可以的,黑色父节点可以连接黑色子节点。
(5)任意节点到每个叶子结点带你的路径都包含相同数量的黑节点,俗称黑高。
(6)性质5可以推出:如果一个叶子结点存在黑色结点,那么该节点肯定有两个子节点。
(7)红黑树的最大高度:2*log2(n+1),即时间复杂度为O(log2n),和平衡二叉树的搜索效率是一样的。
(8)红黑树并不是一个完美的平衡二叉查找树,但是任意一个节点到叶子结点的路径都包含数量相同的黑色节点,所以我们称红黑树为黑色完美平衡

5.2在红黑树中插入结点

(1)如果树是空树,那么插入的节点就是黑色的根结点。
(2) 加入不是空树,插入新节点总是将其标记为红色,如果其父节点是黑色,满足红黑树的性质,完成插入了,不做任何操作;如果插入节点的父节点是红色,这时候就不满足红黑树的性质了,不能连续父子节点都是红色的,这时候需要做调整。我们先构造一棵空的红黑树,插入第一个节点,因为是根节点所以是黑色的,值为8;然后插入5,新插入节点为红色,为根节点8的左子树;然后再插入一个新的红色节点18,为根节点的右子树,如下图所示:
在这里插入图片描述
(3)如果新节点的父节点是红色节点,就要检查父节点的兄弟节点是什么颜色,加入兄弟是红色的,那就直接将父节点和父节点的兄弟节点的颜色全部反转一下,从红色变成黑色,并且检查父节点的父节点是否为根节点,如果父节点的父节点不是根节点那么就需要重新着色,如果是根节点就不重新着色。15的的父节点18也是红色的,此时我们需要检查父节点的兄弟节点的颜色,发现他们是红色,所以我们需要将节点15的父节点以及父节点的兄弟节点换成黑色,并检查15的父节点的父节点是否为根节点,发现是根节点,就不做任何操作了。如下图:
在这里插入图片描述
(4)如果插入节点的父节点的兄弟为黑色或没有,那么这时候就需要适当旋转,并重新着色。接下来我们插入17,发现它的父节点是15为红色,节点15没有兄弟节点。此时需要做LR旋转并重新着色如下图:

在这里插入图片描述

(5)如果插入节点的父节点是红色,并且父节点的兄弟节点也是红色的,那么就将父节点以及其兄弟节点重新着色成黑色,并且检查父节点的父节点是否为根节点,如果不是的话就将其重新着色为红色。然后接着进行上述过程之道这棵树变成一棵红黑树。在上述图中继续插入25,如下图所示:

(6)如果父节点是红色的,但是父节点的兄弟节点是黑色或者为空,则需要旋转该树并且重新着色。

在这里插入图片描述

5.3 红黑树自平衡的三种操作:左旋、右旋和着色

(1)着色:节点颜色由红色变成黑色或者从黑色变成红色。
(2)左旋转:以某个节点为支点(旋转节点),其右子节点变为旋转节点的父节点,右子节点的左子节点变为旋转节点的右子节点,左子节点保持不变。
(3)右旋转:以某个节点为支点(旋转节点),其左子节点变为旋转节点的父节点,左子节点的右子节点变为旋转节点的左子节点,右子节点保持不变。
(4)红黑树查找:因为红黑树是一棵二叉平衡树,并且查找不会破坏树的平衡,所以查找根二叉平衡树的查找无异。
(5)红黑树的插入:插入操作主要包括两部分的工作,查找插入位置以及插入后的自平衡。插入的节点必须为红色,理由很简单,红色再父节点为黑色节点的时候,红黑树的黑色平衡没有破坏,不需要做自平衡操作;但是如果插入的节点是黑色,那么插入的位置所在的子树的黑色节点总是多1,必须做自平衡
(6)红黑树插入情景。

  • 场景一:红黑树为空树,最简单一种情景就是直接把插入节点作为根节点就行;
  • 场景二:插入节点的key已经存在,这个时候应该更新当前节点的值为插入节点的值;
  • 场景三:插入接待你的父节点为黑色节点。由于插入节点是红色的,当插入节点的父节点是黑色的时候,不会影响树的平衡,直接插入即可,不需要做自平衡。
  • 场景四:插入节点的父节点为红色,并且父节点的兄弟节点也为红色,此时插入子树的红黑层数的情况是:黑红红,显然处理方式是把其改为:红黑红,即把父节点和父节点的兄弟节点改为黑色节点,将父节点的父节点改为红色,然后以爷爷节点为当前节点递归进行后续处理。
  • 场景五:插入节点的父节点为红色,并且父节点的兄弟节点不存在或者为黑色节点,并且插入节点的父节点是祖父节点的左子树,即新插入节点为其父节点的左子节点,那么此时需要进行LL红色情况(右单旋转),此时先变色后LL旋转;如果插入节点是其父节点的右子节点,那么要执行LR操作(先左旋转后右旋转),此时先变色右LR旋转;RR和RL均是这样

六、B树

6.1B树介绍

B树又叫做多路平衡查找树,B树中所有接待你的孩子葛叔的最大值为B树的阶,通常用m表示,一棵m阶的树或为空树,或为满足下面特性的m叉树:

  • 树中的每个节点最多有m棵子树,即至多右m-1个关键字;
  • 若根节点不是终端节点,则至少有两棵子树;
  • 除根节点之外的所有非叶子结点至少有m/2向上取整棵子树,即至少包含m/2向上取整-1个关键字。
  • 所有叶子结点都出现在同一层次,并且不带信息
  • B树是所有节点的平衡因子均为0的多路平衡查找树
  • 节点孩子的个数等于该节点中关键字的个数加1
  • 如果节点没有关键字就没有子树,此时B树为空;如果根节点有关键字,则其子树必然大于等于两棵,因此子树个数为关键字个数加1.
  • 除根节点外的所有非终端节点至少有m/2向上取整棵子树
  • 节点中关键字从左向右递增有序,关键字两侧均有指向子树的指针,左边指针所指向的子树的所有关键字均小于该关键字,右边指针所指向的子树的关键字均大于该关键字。或者可以看成下层节点关键字总是落在上层节点关键字所划分的区间内。
  • 叶子节点代表查找失败的

6.2B树的高度(磁盘存取的次数)

B树中大部分操作所需要的磁盘存取次数和高度成正比。B树的高度不包括最后不带任何信息的叶节点所处的那一层,对于有n个关键字,高度为h,阶数为m的b树,有:h>=logm(n+1);如果让每个节点中的关键字个数达到最小,则容纳相同关键字的B树高度达到最大。

6.3B树的查找

B树的查找包含两个操作:在B树中查找节点;在节点内查找关键字。由于B树是存储在磁盘上的,所以前面的在B树中查找节点操作是在次哦安上进行的,而在节点内查找是在内存中进行的。就是说在找到目标节点之后,先将节点信息读取到内存,然后在节点内部采用顺序查找或者折半查找。

6.4B树的插入

(1)定位。先利用B树查找算法,找到插入该关键字的最底层中某个非叶子结点,在B树中找key的时候,会找到表示查找失败的叶子结点,这样就能确定了最底层非叶子结点的插入位置,这里要注意:插入位置一定是最底层某个非叶子结点
(2)插入。如果插入后挂件子个数小于m,则可以直接插入;如果插入后关键字个数大于m-1的时候,必须进行分裂。

6.5B树的删除

七、B+树

(1)B+树中,具有n个关键字的节点只包含n棵子树
(2)B+树中,每个节点关键字个数n的范围为:m/2<=n<=m
(3)B+树中每个叶子结点只起到索引的作用,非叶子结点中的每个索引项只包含对应子树中最大关键字和指向孩子的指针,不含有关键字对应记录的存储地址。
(4)B+树叶子结点包含全部的关键字,即在非叶子结点中出现的关键字也会出现在叶子结点中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值