一、二叉树
二叉树可以使用一个链表数据结构来表示,其中每个结点就是一个对象。除了
设
1. 插入
假设有这样一组数







是一个左右子树大小相对差不多的二叉树,同样的一组数,我们改变下排序,按照

由于升序插入,新插入的数据总是比已存在的结点数据都要大,所以每次都会往结点的右边插入,导致严重右斜。一颗树退化为一个线性链表,查找效率变的很低
2. 遍历

- 中序遍历:根的关键字
位于其左子树的关键字值和右子树的关键字之间。中序遍历输出为:
- 先序遍历:根的关键字在其左右子树的关键字值之前。前序遍历输出为:
- 后序遍历:根的关键字在其左右子树的关键值之后。后续遍历输出为:
3. 删除
从一颗二叉搜索树中删除一个结点
- 如果
没有孩子结点,那么只是简单地将它删除,并修改它的父结点,用
做为孩子来替换
。
- 如果
只有一个孩子,那么将这个孩子提升到树中
的位置上,并修改
的父结点,用
的孩子来替换
。
- 如果
有两个孩子,那么找
的后继
(一定在
的右子树中,大于
的最小关键字的结点,且
结点一定没有左子树,否则
不是最小关键字的结点),并让
占据树中
的位置,如果
存在右子树
,让
占据
位置。
原来左子树成为
的新左子树,
原来右子树成为
的新右子树。
二、平衡二叉树
平衡二叉树是一种特殊的二叉树,满足二叉树的特性,同时还有一个特性:它的左右两个子树的高度差的绝对值不超过
1. 插入
在所有的不平衡情况中,都按照先寻找最小不平衡树,然后寻找不平衡类别,只需要一次或两次旋转来恢复平衡,根据以下四种情况进行旋转。
- LL:在 A 左子树的左子树插入结点而破坏平衡——右旋转。
- RR:在 A 右子树的右子树插入结点而破坏平衡——左旋转。
- LR:在 A 左子树的右子树插入结点而破坏平衡——先左旋后右旋。
- RL:在 A 右子树的左子树插入结点而破坏平衡——先右旋后左旋。




我们还是以下面这组数为例







这颗树始终满足平衡二叉树的几个特性而保持平衡,避免了树退化为线性链表,查找效率和二分法查找一样。
2. 删除
和删除二叉树操作情况一致,分为上面三种情况,但是平衡二叉树删除结点后需要重新检查平衡性并修正。
1) 删除叶子结点
- 将该结点直接从树中删除;
- 通过向上遍历,计算其父结点是否失衡;
- 如果父结点未失衡,则继续向上遍历父结点的父结点并计算是否失衡,反复直到根结点;
- 如果父结点失衡,则判断是哪种失衡类型
,并对其进行相应的平衡化处理。处理后,如果发现以父结点为根结点的树的高度发生变化,继续遍历;如果高度未变化,说明祖先结点的高度不会有变化,可以直接退出。

2)删除的结点只有左子树或者右子树
- 将左子树或右子树替代原来删除结点的位置;
- 从删除结点位置向上遍历判断是否失衡,具体做法和上面一样。

3)删除的结点既有左子树又有右子树
- 具体参考二叉树第三种删除情况;
- 从后继结点的父结点开始向上遍历是否失衡,具体和前面一样。

一颗平衡树能容纳的结点数和树的高度有关系,假设树的高度为
我们数据库中的数据基本都是存放在磁盘中,每次读取一个二叉树的结点就是一次磁盘 IO,这样我们找一条数据需要
三、B 树
B 树是为磁盘或其他直接存取的辅助存储设备而设计的一种平衡搜索树,每个结点可以有很多孩子。一颗 B 树有如下特性:
- 每个结点
有下面属性:1)
当前存储在结点
中的关键字个数;2)
个关键字降序存放,使得
3)
一个布尔值,如果
是叶结点,则为
;如果
是内部结点,则为
。
- 每个内部结点
还包含
个指向其孩子的指针
叶结点没孩子,所以它们的
属性没有定义。
- 关键字
对存储在各个子树中的关键字范围加以分割:如果
为任意一个存储在以
为根的子树中的关键字,那么:
- 每个叶子结点具有相同的深度,即树的高度
。
- 每个结点所包含的关键字个数有上界和下界。用一个称为 最小度数固定整数
树的
来表示。1)除了根结点以外的每个结点必须至少有
个关键字。因此除了根结点以外的每个内部结点至少有
个孩子。2)每个结点至多可包含
个关键字。因此内部结点至多可有
个孩子。当一个结点恰好有
满的。个关键字时,称该结点时
1. 插入
由于不能将关键字插入一个满的叶子结点,故引入一个操作,将一个满的结点
假设这样一组数据












2. 删除
- 如果关键字
在结点
中,并且
是叶结点,则从
中删除
。
- 如果关键字
在结点
中,并且
是内部结点,则做以下操作:1)如果结点
中前于
的子结点
至少包含
个关键字,则找出
在以
为根的子树中的前驱
,删除
,并在
中用
代替
;2)如果
有少于
个关键字,则检查结点
中后于
的子结点
。如果
至少有
个关键字,则找出
在以
为根的子树中的后继
,删除
,并在
中用
代替
;3)否则,如果
和
中都只含有
的关键字,则将
合并进
中,删除结点
中的
和指向
的指针。
- 如果关键字
不在当前内部结点
中,但是
在
指向的子树中,如果
只有
个关键字,则做以下操作:1)
的一个相邻的兄弟至少包含
个关键字,则将
中的某一个关键字降至
中,将
该相邻兄弟的一个关键字升至
,将该兄弟相应的孩子指针移动到
中;2)如果
和其所有相邻的兄弟都只包含
个关键字,则将
与一个兄弟合并,即将
的一个关键字移动至新合并的结点,使之成为该结点的中间关键字。




四、B+树
B+树是由 B-树衍生来的,更适合实现外存储索引结构,具有特性:
- 所有的非叶子结点只存关键字信息;
- 所有卫星数据都存在叶子结点中;
- 所有的叶子结点中包含了全部的数据信息;
- 所有叶子结点之前用指针连接。
假设一组数据

B-树和B+树的优劣:
- B-树非叶子结点也保存了具体数据,所以在查找某个关键字的时候找到即可返回。而B+树所有数据都在叶子结点,每次查找都要到叶子结点,所以在同样高度的B-树和B+树中,B-树查找某个关键字的效率更高点;
- 由于B+树所有数据都在叶子结点,并且结点之间有指针连接,在找大于某个关键字或者小于某个关键字的数据时候,B+树只需要找到该关键字然后沿着链表遍历就可以了,而B-树还需要遍历该结点的根结点去搜索;
- 由于B-树的每个结点都存储关键字+实际数据,而B+树非叶子结点只存储关键字信息,而每页的大小是有限的,所以同一页能存储B+树的数据更多;同样总量的数据,B-的深度会更大,增大查询时磁盘 I/O 次数,进而影响查询效率。
在关系型数据库中,都是选择 B+树的数据结构来存储数据。