红黑树的定义:
红黑树中以一条左下的红链接表示3节点。黑链接表示2-3书中的普通链接
左倾红黑树:红链接必须为左连接、没有任何一个结点同时和两天红链接相连。
红黑树的节点颜色非红即黑
左倾红黑树总结:
又可以换成更通俗易懂的话:
1、节点是红色或黑色。
2、根是黑色。
3、所有叶子都是黑色(叶子是NIL节点)。
4、每个红色节点必须有两个黑色的子节点。(从叶子到根之间不能有两个连续红色节点)
5、从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点
代码实现红黑树:
红黑树是在2-3查找树的基础上进行演变的,其中值得注意的是创建节点时默认颜色为红色。
1、假如任意插入的节点是黑色节点,则连续插入两个黑色节点后,就不满足第四点性质(肯定有一边的黑色节点多于另外一边);
2、但是连续插入两个红色节点就不会破坏性质四,因为连续两个红色节点可以根据红黑树的变换规则进行变色或者旋转的调整,以达到标准的红黑树!
至于为什么连续插入两次黑节点就破坏了红黑树性质可以看这篇文章:一文彻底理解红黑树_码爱爸爸的博客-CSDN博客
class RBT1<E> where E : IComparable<E>
{
private const bool Red = true;
private const bool Black = false;
private class Node
{
public E e;
public Node left;
public Node right;
public bool color;//除了设置左右节点外还要设置节点颜色,true代表红节点,flase代表黑节点
public Node(E e)
{
this.e = e;
left = null;
right = null;
color = Red;//创建节点默认为红色,因为融合操作
}
}
private Node root;
private int N;
设置一个函数判断节点颜色
private bool IsRed(Node node)
{
if (node == null)
return Black;
return node.color;
}
红黑树左旋转
当右节点为红色左节点为黑色,进行左旋转操作。
代码实现:
左旋转是添加方法中的一个步骤因此设为private私有成员。
// node x
// / \ 左旋转 / \
// T1 x ---------> node T3
// / \ / \
// T2 T3 T1 T2
//返回左旋转后新的二叉查找树的根,对新的二叉查找树进行后续的修复操作
//左旋转过程中保证二叉树的性质,左子树都比根节点小,右子树都比根节点大
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;
红黑树颜色翻转和右旋转
当左右子结点均为红色,进行颜色翻转
由于10为根结点,再把10变成黑色
代码实现:
//颜色翻转
private void FlipColors(Node node)
{
node.color = Red;
node.left.color = Black;
node.right.color = Black;
}
右旋转
然后此时左右孩子都为红节点,进行FilpColor翻转。
代码实现:
// node x
// / \ 右旋转 / \
// x T2 -------> T3 node
// / \ / \
// T3 T1 T1 T2
//返回右旋转后新的二叉查找树的根,对新的二叉查找树进行后续的修复操作
//右旋转过程中保证二叉树的性质,左子树都比根节点小,右子树都比根节点大
private Node RightRoatate(Node node)
{
Node x = node.left;
node.left = x.right;
x.right = node;
x.color = node.color;
node.color = Red;
return x;
}
红黑树添加功能:
//往红黑树中添加元素,递归实现
public void Add(E e)
{
root = Add(root, e);
root.color = Black;//根节点一定为黑色
}
//以node为根的树中添加元素e,添加后返回根节点node
private Node Add(Node node, E e)
{
if (node == null)
{
N++;
return new Node(e); //默认为红结点
}
if (e.CompareTo(node.e) < 0)
node.left = Add(node.left, e);
else if (e.CompareTo(node.e) > 0)
node.right = Add(node.right, e);
//如果出现右子结点是红色,而左子结点是黑色,进行左旋转
if (IsRed(node.right) && !IsRed(node.left))
node=LeftRotate(node);
//如果出现连续的左子结点都为红色,进行右旋转
if (IsRed(node.left) && IsRed(node.left.left))
node=RightRoatate(node);
//如果出现左右子结点均为红色,进行颜色翻转
if (IsRed(node.left) && IsRed(node.right))
FlipColors(node);
return node;
}
红黑树的生长轨迹(升序构造)