红黑树(也是一棵二分搜索树)
1.每个节点或者是红色的,或者是黑色的
2.根节点是黑色的
3.每一个叶子节点(最后的空节点)是黑色的
4.如果一个节点是红色的,那么他的孩子节点都是黑色的
5.从任意一个节点到叶子节点,经过的黑色节点是一样的
6.红黑树是保持“黑平衡”得二叉树
7.红黑树红色节点都是向左倾斜的
红黑树与2-3树等价
1.2-3树满足二分搜索树的基本性质
2.节点可以存放一个或者俩个元素
3.每个节点有2个或者3个孩子(有俩孩子,叫做二节点,有三个孩子,叫做三节点)
2-3树添加元素
4.2-3树是一颗绝对平衡的树(也就是二三节点融合)在我们前面的二分搜索树中我们知道,左子树的元素值一定小于根节点,右子树的值大于根节点,因此我们往2-3树中添加元素也要遵循这一点,假如他是一个2节点,则添加时直接编程三节点,假如是三节点,则就变成了四节点,四节点又会变成三个二节点,依次类推,保持绝对平衡,添加节点一定不会添加到空位置,从根节点直到叶子节点
1.如果插入三节点为叶子节点,父亲节点为2节点
插入的元素与根节点进行融合形成一个3节点
2.如果插入三节点为叶子结点,父亲节点为3节点
插入元素与父亲节点进行融合形成一个4节点,将4节点拆成3个二节点,然后再继续向上融合,以此类推
公共代码如下
private static final boolean RED = true;
private static final boolean BLACK = false;
private class Node {
public K key;
public V value;
public Node left, right;
public boolean color;
public Node(K key, V value) {
this.key = key;
this.value = value;
left = null;
right = null;
color = RED;
}
}
private Node root;
private int size;
public RBTree() {
root = null;
size = 0;
}
public int getSize() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
颜色的反转
将黑色变为红色,红色变为黑色,与2-3树的4节点类似
具体的实现代码如下
//颜色翻转
private void filpColor(Node node) {
node.color = RED;
node.left.color = BLACK;
node.right.color = BLACK;
}
右旋转
将孩子节点的右子树连接到父亲节点的左子树,然后将父亲节点连接到孩子节点的右子树,将父亲节点变为红色,孩子节点变为黑色(颜色反转)具体的实现代码如下
//红黑树的右旋转
private Node rightRotate(Node node) {
Node x = node.left;
//右旋转
node.left = x.right;
x.right = node;
x.color = node.color;
node.color = RED;
return x;
}
左旋转
将孩子节点的左子树连接到父亲节点的右子树,然后将父亲节点连接到孩子节点的左子树,将父亲节点变为红色,孩子节点变为黑色(颜色反转)具体的实现代码如下
//红黑树的左旋转
private Node leftRotate(Node node) {
Node x = node.right;
//左旋转
node.right =x.left;
x.left = node;
x.color = node.color;
node.color = RED;
return x;
}
2-3树的三节点就相当于红黑树中父亲孩子节点,三节点中较大的数作为父亲节点,较小的数作为孩子节点
红黑树添加新元素(永远添加红色节点)
与2-3添加新的元素类似,如果树为空,直接添加即可,然后把红色变为黑色(颜色翻转),如果不是的话直接类似2-3树的添加元素,将根节点变为黑色,孩子节点为红色,如果添加元素是在左子树,直接添加,如果在右子树,我们需要进行左旋转,同时节点互换,如果在2-3树节点中间添加元素,那么就需要进行对孩子左旋转,在进行对父亲节点右旋转,最后进行颜色翻转。
1.右孩子为红色节点,左孩子不是红色节点。(进行左旋转,颜色翻转)
2.左孩子为红色节点,左孩子的左孩子为红色节点(进行右旋转,颜色翻转)
3.左孩子和右孩子都为红色节点,(直接进行颜色翻转)
具体的实现代码如下:
// 向以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(node.right, key, value);
} else {
node.value = value;
}
//红黑树的维护
if(isRed(node.right) && !isRed(node.left)) {
node = leftRotate(node);
}
if(isRed(node.left) && isRed(node.left.left)) {
node = rightRotate(node);
}
if(isRed(node.left) && isRed(node.right)) {
flipColor(node);
}
return node;
}
红黑树的性能总结
1.对于完全随机的数据,普通的二分搜索树很好用
缺点:极端情况退化成链表(或者高度不平衡)
2.对于查询较多的使用情况,AVL树很好用!
3.红黑树牺牲了平衡性,统计性能更优(综合增删改查所有操作)
以上就是我对红黑树与2-3树的理解,不喜勿喷,谢谢!