红黑树(RB-Tree)
结点增加颜色,用非严格的平衡换取增删结点时旋转次数的降低。
时间复杂度:O(lgn)
插入、删除效率更高,适用于 STL、Linux进程调度等操作性能稳定的工业级应用。
红黑树结点
/// <summary>
/// 红黑树结点
/// </summary>
internal class RBNode<T> : BTNode<T> where T : IComparable<T>
{
/// <summary>
/// 当前父结点
/// </summary>
public new RBNode<T> Parent
{
get { return (RBNode<T>)base.Parent; }
set { base.Parent = value; }
}
/// <summary>
/// 左子结点
/// </summary>
public new RBNode<T> LeftChild
{
get { return (RBNode<T>)base.LeftChild; }
set { base.LeftChild = value; }
}
/// <summary>
/// 右子结点
/// </summary>
public new RBNode<T> RightChild
{
get { return (RBNode<T>)base.RightChild; }
set { base.RightChild = value; }
}
/// <summary>
/// 红黑树结点的颜色
/// </summary>
public RedBlackTreeColors Color { get; set; }
/// <summary>
/// 兄弟结点
/// </summary>
public RBNode<T> Sibling
{
get => Parent == null ? null : (IsLeftChild ? Parent.RightChild : Parent.LeftChild);
}
/// <summary>
/// 祖父结点
/// </summary>
public RBNode<T> GrandParent
{
get => Parent == null ? null : Parent.Parent;
}
/// <summary>
/// 结点是否为红色,true红色
/// </summary>
public bool IsRed { get => Color == RedBlackTreeColors.Red; }
/// <summary>
/// 结点是否为黑色,true黑色
/// </summary>
public bool IsBlack { get => Color == RedBlackTreeColors.Black; }
public RBNode() : this(default, null, null, null) { }
public RBNode(T value) : this(value, null, null, null) { }
public RBNode(T value, RBNode<T> parent, RBNode<T> left, RBNode<T> right) : base(value, parent, left, right)
{
// 新结点初始颜色都为红色
Color = RedBlackTreeColors.Red;
}
public override string ToString()
{
if (Color == RedBlackTreeColors.Red)
{
return $"{Data}о";
}
return $"{Data}●";
}
}
/// <summary>
/// 红黑树结点颜色类型
/// </summary>
enum RedBlackTreeColors
{
[Description("红色")]
Red = 1,
[Description("黑色")]
Black = 2,
};
实现
/// <summary>
/// 红黑树
/// </summary>
public class RedBlackTree<T> : BinarySearchTree<T> where T : IComparable<T>
{
/// <summary>
/// 哨兵
/// </summary>
internal readonly RBNode<T> _nIL;
/// <summary>
/// 根结点
/// </summary>
internal new RBNode<T> Root
{
get => (RBNode<T>)base.Root;
set { base.Root = value; }
}
public RedBlackTree() : base()
{
_nIL = new RBNode<T>()
{
Color = RedBlackTreeColors.Black,
};
}
public override void Insert(T item)
{
var node = new RBNode<T>(item);
if (!InsertNode(node))
{
throw new InvalidOperationException("树不允许插入重复元素" + item.ToString());
}
// 调整树,满足红-黑树的属性 红父 要调整
InsertFixup(node);
//AdjustTreeAfterInsertion(node);
//Root.Color = RedBlackTreeColors.Black;
}
/*
不能只是简单的调用基类方法。
处理过程类似,但是多一些颜色的处理。
*/
public override void Remove(T item)
{
if (IsEmpty)
{
throw new Exception("树是空的");
}
// TODO 可参考BST删除过程
}
/// <summary>
/// 判断结点颜色,true黑色,false红色
/// </summary>
/// <param name="node">结点</param>
/// <returns></returns>
private bool CheckIsBlack(RBNode<T> node)
{
return (node == null // 哨兵,叶子结点
|| (node != null && node.IsBlack)); // 内部结点
}
/// <summary>
/// 判断结点颜色,true红色,false黑色
/// </summary>
/// <param name="node">结点</param>
/// <returns></returns>
private bool CheckIsRed(RBNode<T> node)
{
return (node != null && node.IsRed); // 内部结点才有红色
}
}
其他具体实现,同学们可根据红黑树的特点,自行补充完善。
应用
public void Test()
{
var bst = new BinarySearchTree<int>();
var rbTree = new RedBlackTree<int>();
int[] values = new int[] { 11, 2, 14, 1, 7, 15, 5, 8 };
bst.Insert(values);
WsCommFunc.ConsoleWriteLine(bst.ToString(TraversalMode.LevelOrder));
Console.WriteLine(TreeDrawer.DrawTree(bst));
Console.WriteLine("AVL树调整频繁。。。。。。改为红黑树");
rbTree.Clear();
foreach (var item in values)
{
Console.WriteLine("插入 " + item.ToString() + " case1,只变色不旋转");
rbTree.Insert(item);
WsCommFunc.ConsoleWriteLine(TreeDrawer.DrawTree(rbTree));
}
Console.WriteLine("插入 4. case1,case2,case3......");
rbTree.Insert(4);
WsCommFunc.ConsoleWriteLine(TreeDrawer.DrawTree(rbTree));
Console.WriteLine("Ex2......");
values = new int[] { 41, 38, 31, 12, 19, 8 };
rbTree.Clear();
foreach (var item in values)
{
Console.WriteLine("插入 " + item.ToString());
rbTree.Insert(item);
WsCommFunc.ConsoleWriteLine(TreeDrawer.DrawTree(rbTree));
}
Console.WriteLine("删除 8 ");
rbTree.Remove(8);
WsCommFunc.ConsoleWriteLine(TreeDrawer.DrawTree(rbTree));
Console.WriteLine("删除 12 ");
rbTree.Remove(12);
WsCommFunc.ConsoleWriteLine(TreeDrawer.DrawTree(rbTree));
Console.WriteLine("删除 19 ");
rbTree.Remove(19);
WsCommFunc.ConsoleWriteLine(TreeDrawer.DrawTree(rbTree));
Console.WriteLine("删除 31 ");
rbTree.Remove(31);
WsCommFunc.ConsoleWriteLine(TreeDrawer.DrawTree(rbTree));
Console.WriteLine("删除 38 ");
rbTree.Remove(38);
WsCommFunc.ConsoleWriteLine(TreeDrawer.DrawTree(rbTree));
Console.WriteLine("删除 41 ");
rbTree.Remove(41);
WsCommFunc.ConsoleWriteLine(TreeDrawer.DrawTree(rbTree));
}