目录
整体结构思维导图
-------------------------------------------------------------------------------- 回到目录
什么是2-3树
2-3树:满足二分搜索树的基本性质,节点可存放一个元素或两个元素,是一棵绝对平衡的树(任意子树左右高度差为0)。
2-3树插入元素
一个原则: 添加节点将永远不会添加到一个空的位置(这和二叉搜索树不同),只会和最后找到的叶子节点做融合。
添加方法:
0、从根节点开始寻找到要插入的父亲节点。
1、若节点小于父亲节点,就融合到左边,大的就融合到右边。
2、若融合完后父亲节点变成4节点(父亲节点有3个元素,4个孩子),就把父亲节点从中间元素分裂,否则完成当前节点的添加。
3、若分裂完后的父亲节点的父亲节点不是4节点,就重复1、2步骤。
分裂图示:
初级图示:
中级图示:
高级图示:
-------------------------------------------------------------------------------- 回到目录
2-3树与红黑树关系
2-3树与红黑树是等价的,红黑树只不过是在2-3树的基础上做一些人为规则的约定:
以下实现的红黑树是左倾红黑树。
关于颜色:
2节点都是黑色,3节点中小的元素红色,大的元素黑色:(即红色节点永远左倾)
完整图示:
上图直观的图示:
-------------------------------------------------------------------------------- 回到目录
红黑树性质
1-4点可对照上上图的图示理解,重点是第5点。
第5点: 其最主要的原因是2-3树是绝对平衡的,其次是每个3节点都有一个黑色节点,所以不管怎么走经过的黑色节点的数量是一样多的。
所以红黑树是保持"黑平衡"的二叉树,本质就是2-3树是绝对平衡的。
红黑树严格意义上并不是平衡二叉树,因为平衡因子有可能大于1,但因为“黑平衡”的存在,所以也可看成是平衡二叉树。
红黑树添加元素
首先,新插入的节点永远是红色的。 空节点是黑色的。
添加步骤:
0、从根节点开始寻找到要插入的父亲节点,若是插入第一个节点,则插入后变成黑色。
1.1、若父亲节点没有左孩子,则:
若节点小于父亲节点,则插入到左孩子,保持红色不变;
(插入后左黑,右黑)(保持不变)
若节点大于父亲节点,则插入到右孩子后进行左旋转,对孩子节点和父亲节点进行变颜色,红色变黑色,黑色变红色。
(插入后左黑,右红)(左旋转)
1.2、若父亲节点有左孩子,则:
1.2.1 若节点小于父亲节点的左孩子,则插入到父亲节点的左孩子的左孩子,(a)然后进行右旋转,把父亲节点和父亲节点的左孩子进行变颜色,再把3个节点进行颜色翻转。
(插入后左红,左左红)(右旋转)(颜色翻转)
1.2.2 若节点大于父亲节点的左孩子,则插入到父亲节点的左孩子的右孩子,然后进行左旋转,再进行(a)步骤。
(插入后父亲节点的左孩子左黑,右红)(左旋转)(右旋转)(颜色翻转)
1.2.3 若节点大于父亲节点,则插入到右孩子,然后3个节点进行颜色翻转。
(插入后左红,右红,自己黑)(颜色翻转)
-------------------------------------------------------------------------------- 回到目录
可以看下面添加元素的代码加深添加过程的理解。
添加元素的代码:
/** 向红黑树中添加新的元素(key, value) */
public void add(K key, V value) {
//相当于JDK的put操作
root = add(root, key, value);
root.color = BLACK; /**子过程一: 保持最终根节点为黑色 --> 第二条性质 */
}
// 向以node为根的红黑树树中插入元素(key, value),递归算法,返回插入新节点后红黑树树的根
private Node add(Node node, K key, V value) {
if (node == null) {
size++;
return new Node(key, value);
}
if (key.compareTo(node.key) < 0)
node.left = add(node.left, key, value);
else if (key.compareTo(node.key) > 0)
node.right = add