我们回忆一下AVL树,它在插入和删除节点时,总要保证任意节点左右子树的高度差不超过1。正是因为有这样的限制,插入一个节点和删除一个节点都有可能调整多个节点的不平衡状态。频繁的左旋转和右旋转操作一定会影响整个AVL树的性能,除非是平衡与不平衡变化很少的情况下,否则AVL树所带来的搜索性能提升不足以弥补平衡树所带来的性能损耗。
那有没有绝对平衡的一种树呢?没有高度差也不会有平衡因子,没有平衡因子就不会调整旋转操作。
2-3树正是一种绝对平衡的树,任意节点到它所有的叶子节点的深度都是相等的。
2-3树的数字代表一个节点有2到3个子树。它也满足二分搜索树的基本性质,但它不属于二分搜索树。
1、2-3树定义
一颗2-3树或为一颗空树,或有以下节点组成:
- 2-节点,含有一个元素和两个子树(左右子树),左子树所有元素的值均小于它父节点,右子树所有元素的值均大于它父节点;
- 3-节点,还有两个元素和三个子树(左中右子树),左子树所有元素的值均小于它父节点,中子树所有元素的值都位于父节点两个元素之间,右子树所有元素的值均大于它父节点;
- 子树也是空树、2-节点或者3-节点;
- 没有元素相等的节点。
2、2-3树插入元素(2-3树的构造过程)
插入元素首先进行查找命中,若查找命中则不予插入此元素,如果需要支持重复的元素则将这个元素对象添加一个属性count。若查找未命中,则在叶子节点中插入这个元素。
空树的插入很简单,创建一个节点即可。如果不是空树,插入的情况分为4种:
1.向2-节点中插入元素;
2.向一颗只含有一个3-节点的树中插入元素;
3.向一个父节点为2-节点的3-节点中插入元素;
4.向一个父节点为3-节点的3-节点中插入元素。
向2-节点中插入元素
如果未命中查找结束于2-节点,直接将2-节点替换为3-节点,并将待插入元素添加到其中。
向一颗只含有一个3-节点的树中插入元素
如果命中查找结束于3-节点,先临时将其成为4-节点,把待插入元素添加到其中,然后将4-节点转化为3个2-节点,中间的节点成为左右节点的父节点。如果之前临时4-节点有父节点,就会变成向一个父节点为2-节点的3-节点中插入元素,中间节点与父节点为2-节点的合并。
向一个父节点为3-节点的3-节点中插入元素
插入元素后一直向上分解临时的4-节点,直到遇到2-节点的父节点变成3-节点不再分解。如果达到树根节点还是4-节点,则进行分解根节点,此时树高+1(只有分解根节点才会增加树高),下面动画2-3树插入会出这个例子。
2-3树查找元素
2-3树的查找类似二分搜索树的查找,根据元素的大小来决定查找的方向。要判断一个元素是否存在,我们先将待查找元素和根节点比较,如果它和其中任意一个相等,那查找命中;否则根据比较的结果来选择查找的方向。
2-3树删除
算法4红黑树删除最小键这一小结里没有特别详细地介绍,但给到了沿着左链接向下进行变换的三种情况:
-
如果左子节点不是2-节点,完成;
-
如果左子节点是2-节点,而兄弟节点不是2-节点,将兄弟节点的最小元素移到父节点,父节点的最小元素移到左子节点;
-
如果左子节点是2-节点,而兄弟节点是2-节点,则左子结点、父节点中最小的元素和兄弟结点合并成4-结点。
删除最小元素
我们注意到在叶子节点不是2-节点的时候,删除一个元素是很简单的,而且删除时不考虑自平衡处理。如果删除一个2-节点会留下一个空节点,破坏了2-3树的绝对平衡。所以,为了保证不会删除一个2-节点,可以设定最左边或者最右边进行向下变换节点。这里设置沿最左边的链接,进行向下变换的三种情况正是如上图中,左子节点的父节点除了根节点都会变换成3-节点或4-节点。
删除任意元素
删除任意元素需要进行命中查找。如果查找未命中则忽略之;如果查找命中则向二叉堆一样删除任意元素,将带删除元素右子树的最小元素替换到待删除元素上,然后对右子树进行删除最小元素。
红黑含义
我们来看看红黑树和2-3树的关联,首先,最台面上的问题,红和黑的含义。
- 红黑树中,所有的节点都是标准的2-节点,为了体现出3-节点,这里将3-节点的两个元素用左斜红色的链接连接起来,即连接了两个2-节点来表示一个3-节点。
- 这里红色节点标记就代表指向其的链接是红链接,黑色标记的节点就是普通的节点。
所以才会有那样一条定义,叫“从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点”,因为红色节点是可以与其父节点合并为一个3-节点的,红黑树实现的其实是一个完美的黑色平衡
- 如果你将红黑树中所有的红色链接放平,那么它所有的叶子节点到根节点的距离都是相同的。所以它并不是一个严格的平衡二叉树,但是它的综合性能已经很优秀了。
所以,红黑树的另一种定义是满足下列条件的二叉查找树:
⑴红链接均为左链接。
⑵没有任何一个结点同时和两条红链接相连。(这样会出现4-节点)
⑶该树是完美黑色平衡的,即任意空链接到根结点的路径上的黑链接数量相同。