红黑树的介绍
红黑树的定义:(Red Black Tree)是一种自平衡二叉查找树,能在进行删除和插入操作时通过特定操作保持二叉查找树的平 衡,从而获得较高的查找性能。
红黑树的特点:
1、红黑树是一颗平衡树
2、红黑树节点左右子树的高度差为:长的不能超过短的2倍,这样就牺牲掉了一些平衡,但是提高了删除和插入操作的效率。
* 红黑树的增删查效率高于AVL树
*(旋转次数少很多,但是有节点重新着色)
3、红黑树插入最多旋转两次,删除最多旋转三次
红黑树的性质:
(1)每个节点都有颜色,不是黑色,就是红色
(2)叶子结点(left和right)是黑色(null) null是黑色
(3)根节点root必须是黑色
(4)不能出现连续的红色节点
(5)从根节点root到达每一个叶子结点的路径上,黑色节点的数量都是相同的
红黑树的节点插入:(具体来说就是插入后调整的三种) 1、插入前树是空的,则新插入的根节点必须为黑色
2、插入前树不为空,则新插入的节点应该是红色的,然后检查父亲(parent)节点,如果父亲节点是黑色就插入完成;
如果父亲节点不是黑色就要做插入调整;
当父亲节点为红色时的情况:
情况一:parent节点的兄弟节点为红色(此时先将parent节点和parent节点的兄弟节点同时置为黑色,然后将 parent.parent节点置为红色,然后判断parent.parent节点是否有parent节点,有的话判断它的兄弟节点的颜色,然后重复前面的操作,如果parent.parent节点没有父亲节点,就直接将parent节点置为黑色就完成了)
B.Color = Black;
C.color = Black;
parent.parent = Red;
X = parent.parent;
情况二: parent节点的兄弟节点为黑色,同时新插入的节点、插入节点的parent节点、parent.parent节点在同一侧(先将parent节点的颜色和parent.parent节点的颜色互换,然后以parent.parent节点为根节点右旋)
parent.color = Black;
parent.parent.color = Red;
rightRotate(parent.parent);
情况三:parent节点的兄弟节点为黑色,同时新插入的节点、插入节点的parent节点、parent.parent节点不在同一侧(先以parent节点为根节点左旋,然后按照情况二的操作进行调整)
leftRotate(parent);
parent.color = Black;
parent.parent.color = Red;
rightRotate(parent.parent);
红黑树的插入代码:
public void insert(T data) {
//先判断树是否为空
if(root == null) {
this.root = new Node(data,null,null,null,Color.BLACK);
return;
}
//遍历的方向
RBNode<T> cur = this.root;
RBNode<T> parent = null;
while(cur != null) {
if(cur.getData().compareTo(data) > 0) {
cur = cur.getLeft();
}else if(cur.getData().compareTo() < 0){
cur = cur.getRight();
} else{
return;
}
}
//插入的节点
RBNode<T> node = new RBNode<T>(data,null,null,null,Color.RED);
if(parent.getData().compareTo(data) > 0) {
parent.setLeft(node);
}else{
parent.setRight(node);
}
if(color(parent(node)) == Color.BLACK) {
fixAfterInsert(node);
}
}
private void fixAfterInsert(RBNode<T> node) {
while(color(parent(node)) == Color.RED) {
if (left(parent(parent(node))) == parent(node)) {
//当前节点,父节点在祖先节点的左子树
RBNode<T> uncle = right(parent(parent(node)));
if (color(uncle) == Color.RED) { //插入情况1
setColor(parent(node), Color.BLACK);
setColor(uncle, Color.BLACK);
setColor(parent(parent(node)), Color.RED);
node = parent(parent(node));
}else{
if (node == right(parent(node))){ // 插入情况3前半段
node = parent(node);
leftRotate(node);
}
setColor(parent(node),Color.BLACK);
// 插入情况3后半段和情况2合并
setColor(parent(parent(node)),Color.BLACK);
rightRotate(parent(parent(node)));
break;
}
} else {
// 当前节点,父节点在祖先节点的右树
RBNode<T> uncle = left(parent(parent(node)));
if(color(uncle) == Color.RED){ // 插入情况1
setColor(parent(node), Color.BLACK);
setColor(uncle, Color.BLACK);
setColor(parent(parent(node)), Color.RED);
node = parent(parent(node));
} else {
if(node == left(parent(node))){ // 插入情况3前半段
node = parent(node);
rightRotate(node);
}
setColor(parent(node), Color.BLACK); // 插入情况3后半段和情况2合并
setColor(parent(parent(node)), Color.RED);
leftRotate(parent(parent(node)));
break;
}
}
}
// 有可能向上回溯到根节点跳出,把根节点置成黑色
setColor(this.root, Color.BLACK);
}
private void leftRotate(RBNode<T> node){
RBNode<T> child = node.getRight();
child.setParent(node.getParent());
if(node.getParent() == null){
this.root = child;
} else {
if(node.getParent().getLeft() == node){
node.getParent().setLeft(child);
} else {
node.getParent().setRight(child);
}
}
node.setRight(child.getLeft());
if(child.getLeft() != null){
child.getLeft().setParent(node);
}
child.setLeft(node);
node.setParent(child);
}
private void rightRotate(RBNode<T> node){
RBNode<T> child = node.getLeft();
child.setParent(node.getParent());
if(node.getParent() == null) {
this.root = child;
}
node.setLeft(child.getRight());
child.setRight(node);
}
}
}