红黑树描述
红黑树是一种二叉树,树上的节点分为红色和黑色两种。通过对节点的规则约束,保证每个节点到叶子节点的路径不会相差两倍。红黑树比较复杂,但是它在最坏的情况下,也能保持比较高的效率。
红黑树特点
- 每个节点要么是红的,要么是黑的
- 根节点一定是黑的
- 每个叶子节点一定是黑的
- 如果一个节点时红的,那么他的叶节点一定是黑的
- 每个节点到期子孙叶子节点的路径上所经过的黑色节点数量一致
红黑树旋转
左旋
以B和E的连接为轴,将右侧子节点E向上移动(逆时针旋转)作为父节点
左旋步骤:
1.节点E的父节点(即A)指向节点B的父节点(即A)
2.若节点E的父节点A为空,则节点E将成为新的root节点;如果左旋之前A的左节点为节点B,则现在将A的左节点指向节点E;如果之前A的右节点为节点B,则现在将A的右节点指向节点E
3.将节点E的左节点指向节点B
4.将节点2的父节点指向节点B
5.将节点B的右节点指向节点2
6.将节点B的父节点指向节点E
代码实现如下:
public class TreeMap{
private Node root;//根节点
private void rotateLeft(Node node){
Node newRoot = node.right;
newRoot.parent = node.parent;//节点node的父节点变为节点node.right(newRoot)的父节点
Node A = newRoot.parent;//设置newRoot的父节点为A(即原来节点node的父节点)
if(A == null){//如果A为空,则表示原来node是根节点,则newRoot现在也应该是根节点
root = newRoot;
}else if(A.left == node){//如果A的左节点指向node,则现在A的左节点应该指向newRoot
A.left = newRoot;
}else if(A.right == node){//如果A的右节点指向node,则现在A的右节点应该指向newRoot
A.right = newRoot;
}
node.parent = newRoot;//节点newRoot变为节点node的父节点
newRoot.left.parent = node;//节点newRoot的左节点的父节点指向节点node
node.right = newRoot.left;//节点node的右节点指向节点newRoot的左节点
newRoot.left = node;//节点newRoot的左节点指向node
}
}
class Node{
Node left;
Node right;
Node parent;
}
右旋
以节点E和节点B的连接为轴,将节点E向下移(顺时针旋转)变为子节点
右旋
1.节点B的父节点(即节点A)指向节点E的父节点(即节点A)
2.若发现当前B父节点A为空,则节点B将成为新的root节点;如果节点A的左节点之前为节点E,则现在A的左节点指向节点B;如果A的右节点之前为节点E,则现在A的右节点指向节点B
3.节点2的父节点指向节点E
4.节点E的左节点指向节点2
5.节点B的右节点指向节点E
6.节点E的父节点指向节点B
代码实现如下:
public class TreeMap{
private Node root;//根节点
private void rotateRight(Node node){
Node oldRoot = node.parent;
node.parent = oldRoot.parent;//节点node的父节点指向节点node.parent(oldRoot)的父节点
Node A = node.parent;//设置node的父节点为节点A
if(A == null){//如果原来oldRoot是根节点,那么现在node也应该是根节点
root = node;
}else if(A.left == oldRoot){//如果原来A的左节点是oldRoot,那么现在A的左节点应该是node
A.left = node;
}else if(A.right == oldRoot){//如果原来A的右节点时oldRoot,那么现在A的右节点应该是node
A.right = node;
}
oldRoot.left = node.right;//节点oldRoot的左节点指向node的右节点
node.right.parent = oldRoot;//节点node右节点的父节点指向oldRoot
node.right = oldRoot;//节点node的右节点指向节点oldRoot
oldRoot.parent = node;//节点oldRoot的父节点指向node
}
}
class Node{
Node left;
Node right;
Node parent;
}
红黑树操作
插入
注意事项:
1.新插入的节点,一开始是没有颜色的,但是由于红黑要求每个节点都应该有颜色,所以在插入后要给节点涂色。颜色只有两种——黑色和红色。如果选择黑色的话,由于红黑要求任意节点往下的路径长度(黑色节点的数量)一致,会造成新插入节点的父节点(以及再往上的节点)到下面节点的路径长度不同(不平衡),这时候就需要进行路径的调整;如果选择红色的话,由于红色节点不计入路径长度,那么不管插入哪里,路径都是不会变化的。当然红色节点在红黑数据也有限制——红色节点下面的子节点一定是黑色,所以遇到插入节点的父节点也是红色的时候,也需要进行调整。两者相比较的话,选择黑色是一定要调整的,选择红色的是有可能需要调整,所以选择红色会更加划算一些。在红黑树的调整算法中,新插入节点都会选择红色的。
2.新插入节点会通过比较算法,最终成为某个节点的叶子节点(没有子节点),所以在调整时不需要考虑新插入节点的子节点情况
插入的几种情况:
1.新插入节点的父节点为黑色
在这种情况下新插入的节点对树是没有影响的,因为没有违反红黑树的规则。
2.新插入节点的父节点为红色
在这种情况下由于新插入节点是红色的,导致违反了红黑的规则。需要对红黑树进行调整。
删除