前言
●2-3树是在原来AVL树的基础上提出一种新的树结构,我们都知道二叉搜索树可以加速查询操作,而AVL树在二叉搜索树的基础上限制了高度差(树高=1),从而使得AVL高度平衡。但是AVL树在插入、删除操作方面会引起结构的变化,从而导致结构的多次调整(左旋右旋)。
从没有平衡限制到平衡高度限制,大佬们依然在思考,那么是否有一种树的结构是绝对平衡的呢,也就意味着没有高度差,所有的叶子节点处于同一高度,于是乎2-3树诞生了,2-3树具有二叉搜索的性质,但是它不是一个二叉树。
定义
●在引入2-3树之前,先聊一聊节点,在一般的二叉搜索树中,每个节点至多有两个子树(左、右子树),且左子树所有元素小于其父节点,右子树所有元素大于其父节点。我们称这种节点为2-节点。
那么3-节点的定义也就十分易懂了,节点拥有三个子树,同时3-节点中保存了两个数据。
而子树分为:左、中、右子树,左子树中所有元素小于较小数据,中子树中所有元素位于两个数据之间,右子树中所有元素大于较大数据。
因此2-3树的定义如下:
树节点节点由2-节点或者3-节点组成且所有叶子节点处于同一高度的树(允许是空树)即为2-3树。
性质
1.节点只能为2-节点或者3-节点
2.对于2-节点其有一个数据,两个指针节点
3.对于3-节点其有两个数据,三个指针节点
4.所有叶子节点的高度保持一只高度
查询
●对于一个数据结构,我们基本从三个操作角度去考察,查找、插入、删除操作。
注意:本文树图为绘制方便,部分叶子节点没有绘出,但是请注意非叶子节点,对于2-节点,其必有两个子树,对于3-节点,其必有三个子树!!!
01
查找操作
由于2-3树具有二叉搜索树的性质,因此其查找过程与二叉搜索树相类似,即比较节点数据与目标数据的大小关系,相等则查询到,不等则根据大小关系决定进入哪个子树。
如图:
查询35:
1.与50比较小于50,向左子树移动
2.与40比较小于40,向左子树移动
3.与20、30比较大于20且大于30,向右子树移动
4.与35比较找到35
插入
●插入操作前先进行查询操作,查询到了就不再插入,未查询到则记录查找结束的最后一个节点。
由于树中存在2-节点与3-节点,因此2-3树的插入操作分为四种。
1.向2-节点插入新节点
2.向仅有一个3-节点的树中插入新节点
3.向一个父节点为2-节点的3-节点中插入新节点
4.向一个父节点为3-节点的3-节点插入新节点
01
向2-节点插入新节点
相对其他几种,向2-节点插入元素比较简单,将2-节点转变成3-节点,并将元素插入其中即可。
02
向仅有一个3-节点的树中插入新节点
若插入的节点的是仅有的一个3-节点,那么现将这一3-节点临时变成4-节点,再转化成3个2-节点即将4-节点中中间元素变为左右元素的父节点。
如上:
1.插入35,发现最后查询到的节点为3-唯一的3-节点,那么把35先插入到3-节点中形成4-节点。
2.将4-节点转换成3个2-节点,且将中间元素升为左右元素的父节点,如上图第三个状态。
3.为了保持叶子节点相同高度,将30与40并为一个3-节点。
03
向一个父节点为2-节点的3-节点中插入新节点
该过程其实与向仅有一个3-节点的树中插入新节点相似,先插入为4-节点,再转换,最后往父节点合并成3-节点。
04
向一个父节点3-节点的3-节点中插入新节点
该过程即进行了相当于做了两次向父节点为2-节点的3-节点插入新节点。
如上:
1.插入35,发现最后查询到的节点为父节点为3-节点的3-节点,那么把35先插入到3-节点中形成4-节点。
2.将4-节点转换成3个2-节点,且将中间元素升为左右元素的父节点。
3.因为原父节点为3-节点,中间元素与父节点合并形成了4-节点,所以新形成的4-节点又转换成3个2-节点,新的中间元素再升为左右元素父节点与父节点的父节点合并。
删除
●同样,删除操作也要先进行元素的查找,找到才继续进行删除操作。
删除操作也大致分为三种:
1.删除非叶子结点
2.删除不为2-节点的叶子节点
3.删除为2-节点的叶子节点
01
删除非叶子节点
非叶子结点的删除与重构相对简单,根据中序遍历找到排在删除元素后面的节点元素对删除节点的元素进行覆盖,再删除后继结点即可。
02
删除不为2-节点的叶子节点
该删除操作较为简单,因为不为2-节点的叶子节点,删除其中某一元素并不会改变树的高度,因此直接删除即可。
03
删除为2-节点的叶子节点
对于2-节点的删除相对复杂一些。主要分成四种情况。
04
删除2-节点,父节点为2-节点,兄弟节点3-节点
该过程即进行了相当于做了两次向父节点为2-节点的3-节点插入新节点。
父节点元素替换所要删除节点的元素,兄弟3-节点中较大元素代替父节点元素,兄弟节点转为2-节点。
05
删除2-节点,父节点为2-节点,兄弟节点2-节点
先将删除节点替换成父节点元素,然后通过移动兄弟节点的中序遍历将兄弟节点的后继结点移动到兄弟节点处使得兄弟节点转变成3-节点;然后再进行后续操作。
如上图:
1.将30删除,40替换30
2.原40的后继结点45替换原40
3.原45的后继结点50替换原45
4.原50的后继结点51替换原50
5.原51位于3-节点中因此不需要在考虑后续节点问题
06
删除2-节点,父节点为3-节点
按博主的理解,删除节点其实就是中序遍历删除节点的后继结点替换的过程。
删除2-节点,因为父节点是3-节点,因此可以将父节点的左元素下移替代删除节点即可。
07
2-3树为满二叉树,删除叶子节点
若为满二叉树,那么删除叶子节点,意味着另一子树需要向上与父节点进行合并,父节点的兄弟节点也向上与父节点的父节点进行合并,出现4-节点再进行分解。
如上图:
1.删除45,35与40进行合并成3-节点
2.40的兄弟节点60向上与40的父节点50合并形成3-节点
3.此时叶子节点处于同一高度,树结构重构完毕
结语
●AVL树、2-3树是红黑树的基础,掌握了2-3树对于后续理解红黑树有着很大的帮助。
同时我们注意到,2-3树有着很大的优势,树的平衡度高,对于查询有着很大的优势,然而对于2-、3-节点的维护以及树结构的稳定性会使得该数据结构变得十分复杂。
如有兴趣,可以