前言
红黑树是一种特殊的二叉树,他的优点是插入、删除和查找时间复杂度都是log(n),并且只需要中序遍历就能从小到大遍历节点,常用于解决哈希冲突。
算法思路
实现代码(C#)
using System;
using System.Collections.Generic;
namespace SF_红黑树
{
//颜色枚举
public enum Color
{
RED, //红色
BLACK//黑色
}
//节点
public class TreeNode
{
public int address;//地址值
public Color color;//颜色
public bool isNull = false;//哨兵用
private TreeNode left;//左子节点
private TreeNode right;//右子节点
private TreeNode parent;//父节点
public TreeNode Left
{
get => left; set
{
left = value;
if (value != null) value.parent = this;
}
}
public TreeNode Right
{
get => right; set
{
right = value;
if (value != null) value.parent = this;
}
}
public TreeNode Parent
{
get => parent; set
{
parent = value;
}
}
public TreeNode(int address = 0, TreeNode left = null, TreeNode right = null, TreeNode parent = null)
{
this.address = address;
this.Left = left;
this.Right = right;
this.Parent = parent;
}
//哨兵
public TreeNode(bool isNull)
{
this.isNull = isNull;
this.color = Color.BLACK;
}
public static bool operator <(TreeNode x, TreeNode y)
{
return x.address.CompareTo(y.address) < 0;
}
public static bool operator >(TreeNode x, TreeNode y)
{
return x.address.CompareTo(y.address) > 0;
}
}
public class RBTree
{
//保存根节点
public TreeNode root = null;
//左旋
void LeftRotate(TreeNode x)
{
TreeNode p = x.Parent;
TreeNode y = x.Right;
x.Right = y.Left;
if (p == null)
{
y.Parent = null;
root = y;
}
else
{
if (p.Right == x) { p.Right = y; }
else { p.Left = y; }
}
y.Left = x;
}
//右旋
void RightRotate(TreeNode y)
{
TreeNode p = y.Parent;
TreeNode x = y.Left;
y.Left = x.Right;
if (p == null)
{
x.Parent = null;
root = x;
}
else
{
if (p.Right == y) { p.Right = x; }
else { p.Left = x; }
}
x.Right = y;
}
//插入节点
public void Insert(TreeNode z)
{
TreeNode x = root;
TreeNode y = null;
while (x != null)
{
y = x;
if (z < x) { x = x.Left; }
else { x = x.Right; }
}
if (y == null) { root = z; }
else if (z < y) { y.Left = z; }
else { y.Right = z; }
z.Left = null;
z.Right = null;
z.color = Color.RED;
FixUp_Insert(z);
}
//插入节点后矫正红黑树
void FixUp_Insert(TreeNode z)
{
while (z.Parent != null && z.Parent.color == Color.RED)
{
TreeNode p = z.Parent;
TreeNode pp = z.Parent.Parent;
TreeNode y;
if (p == pp.Left)//父节点是左节点(叔叔为右)
{
y = pp.Right;
if (y != null && y.color == Color.RED)//case1:叔叔节点颜色是红色
{
p.color = Color.BLACK;
y.color = Color.BLACK;
pp.color = Color.RED;
z = pp;
}
else if (z == p.Right)//case2:叔叔节点是黑色,且当前节点是右节点
{
z = p;
LeftRotate(z);
}
else if (z == p.Left)//case2:叔叔节点是黑色,且当前节点是左节点
{
p.color = Color.BLACK;
pp.color = Color.RED;
RightRotate(pp);
}
}
else//父节点是右节点(叔叔为左)
{
y = pp.Left;
if (y != null && y.color == Color.RED)
{
p.color = Color.BLACK;
y.color = Color.BLACK;
pp.color = Color.RED;
z = pp;
}
else if (z == p.Left)
{
z = p;
RightRotate(z);
}
else if (z == p.Right)
{
p.color = Color.BLACK;
pp.color = Color.RED;
LeftRotate(pp);
}
}
}
root.color = Color.BLACK;//根节点颜色置为黑
}
//删除节点
public void Delete(int address)
{
TreeNode z = FindNode(address);
if (z == null) return;
TreeNode y;
if (z.Left == null || z.Right == null) { y = z; }//当前节点的子节点为非双空
else { y = FindSuccessorNode(z); }//当前节点的子节点为双空,找后继节点
TreeNode x = null;
if (y.Left != null) { x = y.Left; }
else { x = y.Right; }
//x作为哨兵不能为空
if (x == null && y.color == Color.BLACK) { x = new TreeNode(true); }
//用y的子节点代替y
if (y.Parent == null) { root = x; }
else if (y.Parent.Left == y) { y.Parent.Left = x; }
else { y.Parent.Right = x; }
if (y != z) { z.address = y.address; }//将y的值赋值给z
if (y.color == Color.BLACK) { FixedUp_Delete(x); }//如果删除的y为黑节点,那么矫正红黑树
}
//查找结点
public TreeNode FindNode(int address)
{
TreeNode y = root;
while (y != null)
{
if (address > y.address) { y = y.Right; }
else if (address < y.address) { y = y.Left; }
else { return y; }
}
return null;
}
//删除节点后矫正红黑树
void FixedUp_Delete(TreeNode x)
{
TreeNode org = x;//记录哨兵
//Console.WriteLine(x.isNull);
while (true)
{
if (x == root || x.color == Color.RED)//如果当前节点是根节点或为红节点
{
x.color = Color.BLACK;
break;
}
TreeNode w;
if (x == x.Parent.Left)//当前节点为左节点
{
w = x.Parent.Right;
if (w != null)//如果当前节点的兄弟节点不为null
{
if (w.color == Color.RED)//case1:当前节点为黑+黑 兄弟节点为红
{
x.Parent.color = Color.RED;
w.color = Color.BLACK;
LeftRotate(x.Parent);
}
else if ((w.Left == null || w.Left.color == Color.BLACK) && (w.Right == null || w.Right.color == Color.BLACK))//case2:当前节点为黑+黑,兄弟节点和其子节点都为黑
{
w.color = Color.RED;
x = x.Parent;
}
else if ((w.Left != null && w.Left.color == Color.RED) && (w.Right == null || w.Right.color == Color.BLACK))//case3:当前节点为黑+黑,兄弟节点为黑,左孩子为红,右孩子为黑
{
w.color = Color.RED;
w.Left.color = Color.BLACK;
RightRotate(w);
w = x.Parent.Right;
}
else if (w.Right != null && w.Right.color == Color.RED)//case4:当前节点为黑+黑,兄弟节点为黑,右孩子为红
{
w.color = x.Parent.color;
x.Parent.color = Color.BLACK;
w.Right.color = Color.BLACK;
LeftRotate(x.Parent);
x = root;
}
}
else
{
x = x.Parent;//反之将当前节点设为父节点
}
}
else//当前节点为右节点(操作和上面相反)
{
w = x.Parent.Left;
if (w != null)
{
if (w.color == Color.RED)
{
x.Parent.color = Color.RED;
w.color = Color.BLACK;
RightRotate(x.Parent);
}
else if ((w.Left == null || w.Left.color == Color.BLACK) && (w.Right == null || w.Right.color == Color.BLACK))
{
w.color = Color.RED;
x = x.Parent;
}
else if ((w.Right != null && w.Right.color == Color.RED) && (w.Left == null || w.Left.color == Color.BLACK))
{
w.color = Color.RED;
w.Right.color = Color.BLACK;
LeftRotate(w);
w = x.Parent.Left;
}
else if (w.Left != null && w.Left.color == Color.RED)
{
w.color = x.Parent.color;
x.Parent.color = Color.BLACK;
w.Left.color = Color.BLACK;
RightRotate(x.Parent);
x = root;
}
}
else
{
x = x.Parent;
}
}
}
//如果哨兵为空,则删除哨兵
if (org.isNull)
{
if (org.Parent == null) { root = null; }
else if (org.Parent.Left == org) { org.Parent.Left = null; }
else { org.Parent.Right = null; }
org = null;
}
}
//寻找后继节点
TreeNode FindSuccessorNode(TreeNode z)
{
TreeNode y = z.Left;
TreeNode ret = null;
while (y != null)
{
ret = y;
y = y.Right;
}
return ret;
}
//中序遍历->左 根 右
public void InOrder(TreeNode node, List<int> ret)
{
if (node == null) return;
InOrder(node.Left, ret);
ret.Add(node.address);
InOrder(node.Right, ret);
}
//输出节点地址信息
public override string ToString()
{
List<int> ret = new List<int>();
InOrder(root, ret);
return string.Join(",", ret);
}
}
}
测试代码
class Program
{
static void Main(string[] args)
{
RBTree rBTree = new RBTree();
Random random = new Random();
List<int> adressArry = new List<int>();
List<int> temp = new List<int>();
for (int i = 0; i < 1000; i++)
{
adressArry.Add(i);
}
//模拟随机分配不同地址
for (int i = 0; i < 20; i++)
{
int index = random.Next(0, adressArry.Count);
TreeNode node = new TreeNode(adressArry[index]);
temp.Add(adressArry[index]);
adressArry.RemoveAt(index);
rBTree.Insert(node);
}
//测试删除
for(int i = 0; i < 10; i++)
{
rBTree.Delete(temp[i]);
}
Console.WriteLine(rBTree.ToString());
}
}
输出
参考文献
1, 《算法导论》(p163-p181)