using System; using System.Runtime.CompilerServices; namespace Assets.Voronoi { public enum RedBlackNodeType { Black, Red } public class RedBlackNode { public T Value { get; internal set; } internal RedBlackNodeType Color { get; set; } = RedBlackNodeType.Red; internal RedBlackNode _left; internal RedBlackNode _right; public RedBlackNode Next => GetSuccessor(); public RedBlackNode Previous => GetPredecessor(); internal RedBlackNode GrandParent => Parent?.Parent; internal RedBlackNode Uncle => Parent?.Parent?.Left == Parent ? Parent?.Parent?.Right : Parent?.Parent?.Left; public RedBlackNode Parent { get; internal set; } public RedBlackNode Right { get => _right; internal set { _right = value; if (value != null) value.Parent = this; } } public RedBlackNode Left { get => _left; internal set { _left = value; if (value != null) value.Parent = this; } } public RedBlackNode(T value = default) { Value = value; } private RedBlackNode GetSuccessor() { RedBlackNode successor, node = this; if (node.Right != null) { successor = node.Right; while (successor.Left != null) successor = successor.Left; return successor; } successor = node.Parent; while (successor != null && successor.Right == node) { node = successor; successor = successor.Parent; } return successor; } private RedBlackNode GetPredecessor() { RedBlackNode predecessor, node = this; if (node.Left != null) { predecessor = node.Left; while (predecessor.Right != null) predecessor = predecessor.Right; return predecessor; } predecessor = node.Parent; while (predecessor != null && predecessor.Left == node) { node = predecessor; predecessor = predecessor.Parent; } return predecessor; } } public class RedBlackTree { private RedBlackNode _root; public RedBlackNode Root { get => _root; internal set { _root = value; _root.Color = RedBlackNodeType.Black; } } public bool IsEmpty => _root == null; public RedBlackNode First { get { var current = _root; while (current?.Left != null) current = current.Left; return current; } } public RedBlackNode Last { get { var current = _root; while (current?.Right != null) current = current.Right; return current; } } public void Rebalance(RedBlackNode node) { while (node != Root && node.Parent.Color == RedBlackNodeType.Red) { if (node.Uncle != null && node.Uncle.Color == RedBlackNodeType.Red) { node.Parent.Color = RedBlackNodeType.Black; node.Uncle.Color = RedBlackNodeType.Black; node = node.GrandParent; } else { (node.Parent.Color, node.GrandParent.Color) = (node.GrandParent.Color, node.Parent.Color); if (node == node.Parent.Left) { if (node.Parent == node.GrandParent.Right) { RotateLeft(node.Parent); } RotateRight(node.GrandParent); } else { if (node.Parent == node.GrandParent.Left) { RotateRight(node.Parent); } RotateRight(node.GrandParent); } } } } public void InsertAfter(RedBlackNode node, T value) { var current = node.Right; var inserted = new RedBlackNode(value); if (current is null) { node.Right = inserted; } else { while (current.Left != null) current = current.Left; current.Left = inserted; } // Rebalance(inserted); } public void InsertBefore(RedBlackNode node, T value) { var current = node.Left; var inserted = new RedBlackNode(value); if (current is null) { node.Left = inserted; } else { while (current.Right != null) current = current.Right; current.Right = inserted; } // Rebalance(inserted); } private void RotateLeft(RedBlackNode current) { var right = current.Right; current.Right = right.Left; right.Left = current; right.Parent = current.Parent; current.Parent = right; FixRoot(current, right); } private void RotateRight(RedBlackNode current) { var left = current.Left; current.Left = left.Right; left.Right = current; left.Parent = current.Parent; current.Parent = left; FixRoot(current, left); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void FixRoot(RedBlackNode old, RedBlackNode current) { if (Root == old) { Root = current; Root.Color = RedBlackNodeType.Black; Root.Parent = null; } } public void Remove(RedBlackNode node) { if (node.Left == null && node.Right == null) RemoveLeaf(node); else if (node.Left == null || node.Right == null) RemoveOneChild(node); else Substitute(node, node.Next); } private void RemoveOneChild(RedBlackNode node) { var replacement = node.Left ?? node.Right; if (Root == node) Root = replacement; else if (node.Parent.Left == node) node.Parent.Left = replacement; else if (node.Parent.Right == node) node.Parent.Right = replacement; else throw new Exception("WTF?"); } private void Swap(RedBlackNode a, RedBlackNode b) { if (b.Parent == a) (a, b) = (b, a); if (a.Parent == b) { if (b.Parent?.Left == b) b.Parent.Left = a; if (b.Parent?.Right == b) b.Parent.Right = a; if (b.Parent == null) a.Parent = null; if (b.Left == a) { (b.Right, a.Right) = (a.Right, b.Right); b.Left = a.Left; a.Left = b; } else { (b.Left, a.Left) = (a.Left, b.Left); b.Right = a.Right; a.Right = b; } } else { (a.Right, b.Right) = (b.Right, a.Right); (a.Left, b.Left) = (b.Left, a.Left); var bparent = b.Parent; if (a.Parent != null && a.Parent.Left == a) a.Parent.Left = b; else if (a.Parent != null && a.Parent.Right == a) a.Parent.Right = b; else b.Parent = null; if (bparent != null && bparent.Left == b) bparent.Left = a; else if (bparent != null && bparent.Right == b) bparent.Right = a; else a.Parent = null; } if (b.Parent == null) Root = b; if (a.Parent == null) Root = a; } private void Substitute(RedBlackNode node, RedBlackNode replacement) { // (node.Value, replacement.Value) = (replacement.Value, node.Value); Swap(node, replacement); Remove(node); } private void RemoveLeaf(RedBlackNode leaf) { if (leaf.Parent == null) { Root = null; return; } if (leaf.Parent.Left == leaf) leaf.Parent.Left = null; else leaf.Parent.Right = null; } } }