AVL Tree/Performance

From Rosetta Code

Red/Black Performance versus AVL Performance

The following C# program was used to test the relative performance of Red/Black Trees versus AVL Trees.

<lang csharp> // SetPerform - Tests Red/Black (3State) Sets against AVL Sets (4State).

using System; using System.Collections.Generic;

//****************************************************************************** //******************************** Red/Black Sets ****************************** //******************************************************************************

public enum Direction { FromLeft, FromRight };

public enum TriState {

   Header,
   Red,
   Black

}

public class RedBlackNode {

   public RedBlackNode Left;
   public RedBlackNode Right;
   public RedBlackNode Parent;
   public TriState Color;
   public bool IsHeader
   { get { return Color == TriState.Header; } }

}


public class RedBlackSetNode<T> : RedBlackNode {

   public T Data;
   public RedBlackSetNode()
   {
       Left = this;
       Right = this;
       Parent = null;
       Color = TriState.Header;
   }
   public RedBlackSetNode(T t)
   {
       Left = null;
       Right = null;
       Color = TriState.Black;
       Data = t;
   }

}

class RedBlackUtility {

   public static ulong Depth(RedBlackNode Root)
   {
       if (Root != null)
       {
           ulong Left = Root.Left != null ? Depth(Root.Left) : 0;
           ulong Right = Root.Right != null ? Depth(Root.Right) : 0;
           return Left < Right ? Right + 1 : Left + 1;
       }
       else
           return 0;
   }
   public static ulong Paths(RedBlackNode Root, ulong weight)
   {
       if (Root != null)
       {
           ulong Left = Root.Left != null ? Paths(Root.Left, weight + 1) : 0;
           ulong Right = Root.Right != null ? Paths(Root.Right, weight + 1) : 0;
           return Left + Right + weight;
       }
       else
           return 0;
   }
   public static RedBlackNode PreviousItem(RedBlackNode RedBlackNode)
   {
       if (RedBlackNode.IsHeader) { return RedBlackNode.Right; }
       if (RedBlackNode.Left != null)
       {
           RedBlackNode = RedBlackNode.Left;
           while (RedBlackNode.Right != null) RedBlackNode = RedBlackNode.Right;
       }
       else
       {
           RedBlackNode y = RedBlackNode.Parent;
           if (y.IsHeader) return y;
           while (RedBlackNode == y.Left) { RedBlackNode = y; y = y.Parent; }
           RedBlackNode = y;
       }
       return RedBlackNode;
   }
   public static RedBlackNode NextItem(RedBlackNode RedBlackNode)
   {
       if (RedBlackNode.IsHeader) return RedBlackNode.Left;
       if (RedBlackNode.Right != null)
       {
           RedBlackNode = RedBlackNode.Right;
           while (RedBlackNode.Left != null) RedBlackNode = RedBlackNode.Left;
       }
       else
       {
           RedBlackNode y = RedBlackNode.Parent;
           if (y.IsHeader) return y;
           while (RedBlackNode == y.Right) { RedBlackNode = y; y = y.Parent; }
           RedBlackNode = y;
       }
       return RedBlackNode;
   }
   static RedBlackNode Minimum(RedBlackNode x)
   {
       while (x.Left != null) x = x.Left;
       return x;
   }
   static RedBlackNode Maximum(RedBlackNode x)
   {
       while (x.Right != null) x = x.Right;
       return x;
   }
   static void RotateLeft(RedBlackNode x,
                          ref RedBlackNode Root)
   {
       RedBlackNode y = x.Right;
       x.Right = y.Left;
       if (y.Left != null)
           y.Left.Parent = x;
       y.Parent = x.Parent;
       if (x == Root)
           Root = y;
       else if (x == x.Parent.Left)
           x.Parent.Left = y;
       else
           x.Parent.Right = y;
       y.Left = x;
       x.Parent = y;
   }
   static void RotateRight(RedBlackNode x,
                           ref RedBlackNode Root)
   {
       RedBlackNode y = x.Left;
       x.Left = y.Right;
       if (y.Right != null)
           y.Right.Parent = x;
       y.Parent = x.Parent;
       if (x == Root)
           Root = y;
       else if (x == x.Parent.Right)
           x.Parent.Right = y;
       else
           x.Parent.Left = y;
       y.Right = x;
       x.Parent = y;
   }
   public static void Rebalance(RedBlackNode x,
                                ref RedBlackNode Root)
   {
       x.Color = TriState.Red;
       while (x != Root && x.Parent.Color == TriState.Red)
       {
           if (x.Parent == x.Parent.Parent.Left)
           {
               RedBlackNode y = x.Parent.Parent.Right;
               if (y != null && y.Color == TriState.Red)
               {
                   x.Parent.Color = TriState.Black;
                   y.Color = TriState.Black;
                   x.Parent.Parent.Color = TriState.Red;
                   x = x.Parent.Parent;
               }
               else
               {
                   if (x == x.Parent.Right)
                   {
                       x = x.Parent;
                       RotateLeft(x, ref Root);
                   }
                   x.Parent.Color = TriState.Black;
                   x.Parent.Parent.Color = TriState.Red;
                   RotateRight(x.Parent.Parent, ref Root);
               }
           }
           else
           {
               RedBlackNode y = x.Parent.Parent.Left;
               if (y != null && y.Color == TriState.Red)
               {
                   x.Parent.Color = TriState.Black;
                   y.Color = TriState.Black;
                   x.Parent.Parent.Color = TriState.Red;
                   x = x.Parent.Parent;
               }
               else
               {
                   if (x == x.Parent.Left)
                   {
                       x = x.Parent;
                       RotateRight(x, ref Root);
                   }
                   x.Parent.Color = TriState.Black;
                   x.Parent.Parent.Color = TriState.Red;
                   RotateLeft(x.Parent.Parent, ref Root);
               }
           }
       }
       Root.Color = TriState.Black;
   }
   static void TSwap<X>(ref X u, ref X v) { X t = u; u = v; v = t; }
   public static RedBlackNode RebalanceForRemove(RedBlackNode z,
                                                 ref RedBlackNode Root,
                                                 ref RedBlackNode Leftmost,
                                                 ref RedBlackNode Rightmost)
   {
       RedBlackNode y = z;
       RedBlackNode x = null;
       RedBlackNode x_Parent = null;
       if (y.Left == null)
           x = y.Right;
       else
           if (y.Right == null)
               x = y.Left;
           else
           {
               y = y.Right;
               while (y.Left != null) y = y.Left;
               x = y.Right;
           }
       if (y != z)
       {
           z.Left.Parent = y;
           y.Left = z.Left;
           if (y != z.Right)
           {
               x_Parent = y.Parent;
               if (x != null) x.Parent = y.Parent;
               y.Parent.Left = x;
               y.Right = z.Right;
               z.Right.Parent = y;
           }
           else
               x_Parent = y;
           if (Root == z)
               Root = y;
           else if (z.Parent.Left == z)
               z.Parent.Left = y;
           else
               z.Parent.Right = y;
           y.Parent = z.Parent;
           TSwap(ref y.Color, ref z.Color);
           y = z;
       }
       else  // y == z
       {
           x_Parent = y.Parent;
           if (x != null) x.Parent = y.Parent;
           if (Root == z)
               Root = x;
           else
               if (z.Parent.Left == z)
                   z.Parent.Left = x;
               else
                   z.Parent.Right = x;
           if (Leftmost == z)
               if (z.Right == null)
                   Leftmost = z.Parent;
               else
                   Leftmost = Minimum(x);
           if (Rightmost == z)
               if (z.Left == null)
                   Rightmost = z.Parent;
               else
                   Rightmost = Maximum(x);
       }
       if (y.Color != TriState.Red)
       {
           while (x != Root && (x == null || x.Color == TriState.Black))
               if (x == x_Parent.Left)
               {
                   RedBlackNode w = x_Parent.Right;
                   if (w.Color == TriState.Red)
                   {
                       w.Color = TriState.Black;
                       x_Parent.Color = TriState.Red;
                       RotateLeft(x_Parent, ref Root);
                       w = x_Parent.Right;
                   }
                   if ((w.Left == null || w.Left.Color == TriState.Black) &&
                       (w.Right == null || w.Right.Color == TriState.Black))
                   {
                       w.Color = TriState.Red;
                       x = x_Parent;
                       x_Parent = x_Parent.Parent;
                   }
                   else
                   {
                       if (w.Right == null || w.Right.Color == TriState.Black)
                       {
                           if (w.Left != null) w.Left.Color = TriState.Black;
                           w.Color = TriState.Red;
                           RotateRight(w, ref Root);
                           w = x_Parent.Right;
                       }
                       w.Color = x_Parent.Color;
                       x_Parent.Color = TriState.Black;
                       if (w.Right != null) w.Right.Color = TriState.Black;
                       RotateLeft(x_Parent, ref Root);
                       break;
                   }
               }
               else
               {
                   RedBlackNode w = x_Parent.Left;
                   if (w.Color == TriState.Red)
                   {
                       w.Color = TriState.Black;
                       x_Parent.Color = TriState.Red;
                       RotateRight(x_Parent, ref Root);
                       w = x_Parent.Left;
                   }
                   if ((w.Right == null || w.Right.Color == TriState.Black) &&
                       (w.Left == null || w.Left.Color == TriState.Black))
                   {
                       w.Color = TriState.Red;
                       x = x_Parent;
                       x_Parent = x_Parent.Parent;
                   }
                   else
                   {
                       if (w.Left == null || w.Left.Color == TriState.Black)
                       {
                           if (w.Right != null) w.Right.Color = TriState.Black;
                           w.Color = TriState.Red;
                           RotateLeft(w, ref Root);
                           w = x_Parent.Left;
                       }
                       w.Color = x_Parent.Color;
                       x_Parent.Color = TriState.Black;
                       if (w.Left != null) w.Left.Color = TriState.Black;
                       RotateRight(x_Parent, ref Root);
                       break;
                   }
               }
           if (x != null) x.Color = TriState.Black;
       }
       return y;
   }
   public static int BlackCount(RedBlackNode RedBlackNode, RedBlackNode Root)
   {
       if (RedBlackNode == null)
           return 0;
       else
       {
           int count = RedBlackNode.Color == TriState.Black ? 1 : 0;
           if (RedBlackNode == Root)
               return count;
           else
               return count + BlackCount(RedBlackNode.Parent, Root);
       }
   }

}

public struct RedBlackSetEntry<T> : IEnumerator<T> {

   public RedBlackSetEntry(RedBlackSetNode<T> n) { RedBlackNode = n; }
   public T Value { get { return RedBlackNode.Data; } }
   public bool IsEnd { get { return RedBlackNode.IsHeader; } }
   public bool MoveNext()
   {
       RedBlackNode = (RedBlackSetNode<T>)RedBlackUtility.NextItem(RedBlackNode);
       return RedBlackNode.IsHeader ? false : true;
   }
   public bool MovePrevious()
   {
       RedBlackNode = (RedBlackSetNode<T>)RedBlackUtility.PreviousItem(RedBlackNode);
       return RedBlackNode.IsHeader ? false : true;
   }
   public void Reset()
   {
       while (!MoveNext()) ;
   }
   object System.Collections.IEnumerator.Current { get { return RedBlackNode.Data; } }
   T IEnumerator<T>.Current { get { return RedBlackNode.Data; } }
   public static bool operator ==(RedBlackSetEntry<T> x, RedBlackSetEntry<T> y) { return x.RedBlackNode == y.RedBlackNode; }
   public static bool operator !=(RedBlackSetEntry<T> x, RedBlackSetEntry<T> y) { return x.RedBlackNode != y.RedBlackNode; }


   public override string ToString() { return Value.ToString(); }
   public void Dispose() { }
   public RedBlackSetNode<T> RedBlackNode;

}


class RedBlackSet<T> : IEnumerable<T> {

   IComparer<T> Comparer;
   RedBlackSetNode<T> Header;
   ulong RedBlackNodes;
   //*** Constructors/Destructor ***
   public RedBlackSet()
   {
       Comparer = Comparer<T>.Default;
       Header = new RedBlackSetNode<T>();
       RedBlackNodes = 0;
   }
   public RedBlackSet(IComparer<T> c)
   {
       Comparer = c;
       Header = new RedBlackSetNode<T>();
       RedBlackNodes = 0;
   }
   //*** Properties ***
   RedBlackSetNode<T> Root
   {
       get { return (RedBlackSetNode<T>)Header.Parent; }
       set { Header.Parent = value; }
   }
   RedBlackSetNode<T> LeftMost
   {
       get { return (RedBlackSetNode<T>)Header.Left; }
       set { Header.Left = value; }
   }
   RedBlackSetNode<T> RightMost
   {
       get { return (RedBlackSetNode<T>)Header.Right; }
       set { Header.Right = value; }
   }
   public RedBlackSetEntry<T> Begin
   { get { return new RedBlackSetEntry<T>((RedBlackSetNode<T>)Header.Left); } }
   public RedBlackSetEntry<T> End
   { get { return new RedBlackSetEntry<T>(Header); } }
   public ulong Length { get { return RedBlackNodes; } }
   public ulong Depth { get { return RedBlackUtility.Depth(Root); } }
   //*** Indexer ***
   public bool this[T Key]
   {
       get
       {
           RedBlackSetNode<T> RedBlackNode = Search(Key);
           if (RedBlackNode == null) return false; else return true;
       }
   }
   //*** Methods ***
   RedBlackSetNode<T> Add(T Key,
                          RedBlackSetNode<T> y,
                          Direction From)
   {
       RedBlackSetNode<T> z = new RedBlackSetNode<T>(Key);
       RedBlackNodes++;
       if (y == Header)
       {
           Root = z;
           RightMost = z;
           LeftMost = z;
       }
       else if (From == Direction.FromLeft)
       {
           y.Left = z;
           if (y == LeftMost) LeftMost = z;
       }
       else
       {
           y.Right = z;
           if (y == RightMost) RightMost = z;
       }
       z.Parent = y;
       RedBlackUtility.Rebalance(z, ref Header.Parent);
       return z;
   }
   public RedBlackSetNode<T> Add(T Key)
   {
       RedBlackSetNode<T> y = Header;
       RedBlackSetNode<T> x = Root;
       int c = -1;
       while (x != null)
       {
           y = x;
           c = Comparer.Compare(Key, x.Data);
           if (c < 0)
               x = (RedBlackSetNode<T>)x.Left;
           else if (c > 0)
               x = (RedBlackSetNode<T>)x.Right;
           else
               throw new EntryAlreadyExistsException();
       }
       Direction From = c < 0 ? Direction.FromLeft : Direction.FromRight;
       return Add(Key, y, From);
   }
   System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
   { return new RedBlackSetEntry<T>(Header); }
   IEnumerator<T> IEnumerable<T>.GetEnumerator()
   { return new RedBlackSetEntry<T>(Header); }
   public void Remove(T Key)
   {
       RedBlackSetNode<T> root = Root;
       for (; ; )
       {
           if (root == null)
               throw new EntryNotFoundException();
           int Compare = Comparer.Compare(Key, root.Data);
           if (Compare < 0)
               root = (RedBlackSetNode<T>)root.Left;
           else if (Compare > 0)
               root = (RedBlackSetNode<T>)root.Right;
           else // Item is found
           {
               RedBlackUtility.RebalanceForRemove(root, ref Header.Parent, ref Header.Left, ref Header.Right);
               RedBlackNodes--;
               break;
           }
       }
   }
   public RedBlackSetNode<T> Search(T Key)
   {
       if (Root == null)
           return null;
       else
       {
           RedBlackSetNode<T> search = Root;
           do
           {
               long result = Comparer.Compare(Key, search.Data);
               if (result < 0) search = (RedBlackSetNode<T>)search.Left;
               else if (result > 0) search = (RedBlackSetNode<T>)search.Right;
               else break;
           } while (search != null);
           return search;
       }
   }
   public override string ToString()
   {
       string StringOut = "{";
       RedBlackSetEntry<T> start = Begin;
       RedBlackSetEntry<T> end = End;
       RedBlackSetEntry<T> last = End; last.MovePrevious();
       while (start != end)
       {
           string NewStringOut = start.Value.ToString();
           if (start != last) NewStringOut = NewStringOut + ",";
           StringOut = StringOut + NewStringOut;
           start.MoveNext();
       }
       StringOut = StringOut + "}";
       return StringOut;
   }
   public void Validate()
   {
       if (RedBlackNodes == 0 || Root == null)
       {
           if (RedBlackNodes != 0) { throw new InvalidEmptySetException(); }
           if (Root != null) { throw new InvalidEmptySetException(); }
           if (Header.Left != Header) { throw new InvalidEndItemException(); }
           if (Header.Right != Header) { throw new InvalidEndItemException(); }
       }
       int Length = RedBlackUtility.BlackCount(LeftMost, Root);
       for (RedBlackSetEntry<T> Iterator = Begin; Iterator != End; Iterator.MoveNext())
       {
           RedBlackSetNode<T> x = Iterator.RedBlackNode;
           RedBlackSetNode<T> L = (RedBlackSetNode<T>)x.Left;
           RedBlackSetNode<T> R = (RedBlackSetNode<T>)x.Right;
           if (x.Color == TriState.Red)
               if ((L != null && L.Color == TriState.Red) ||
                   (R != null && R.Color == TriState.Red))
                   throw new InvalidRedBlackNodeColorException();
           if (L != null && Comparer.Compare(x.Data, L.Data) <= 0)
               throw new OutOfKeyOrderException();
           if (R != null && Comparer.Compare(R.Data, x.Data) <= 0)
               throw new OutOfKeyOrderException();
           if (L == null && R == null &&
               RedBlackUtility.BlackCount(x, Root) != Length)
               throw new InvalidBlackCountException();
       }
       if (Root != null)
       {
           RedBlackSetNode<T> x = Root;
           while (x.Left != null) x = (RedBlackSetNode<T>)x.Left;
           if (LeftMost != x) throw new InvalidEndItemException();
           RedBlackSetNode<T> y = Root;
           while (y.Right != null) y = (RedBlackSetNode<T>)y.Right;
           if (RightMost != y) throw new InvalidEndItemException();
       }
   }

}

public class EntryNotFoundException : Exception {

   static String message = "The requested entry could not be located in the specified collection.";
   public EntryNotFoundException() : base(message) { }

}

public class InvalidEndItemException : Exception {

   static String message = "The validation routines detected that the end item of a tree is invalid.";
   public InvalidEndItemException() : base(message) { }

}

public class InvalidEmptySetException : Exception {

   static String message = "The validation routines detected that an empty tree is invalid.";
   public InvalidEmptySetException() : base(message) { }

}

public class OutOfKeyOrderException : Exception {

   static String message = "A trees was found to be out of Key order.";
   public OutOfKeyOrderException() : base(message) { }

}

public class SetInvalidParentException : Exception {

   static String message = "The validation routines detected that the Parent structure of a tree is invalid.";
   public SetInvalidParentException() : base(message) { }

}

public class InvalidBlackCountException : Exception {

   static String message = "An invalid black node count was encountered.";
   public InvalidBlackCountException() : base(message) { }

}

public class InvalidRedBlackNodeColorException : Exception {

   static String message = "The color of a node is invalid.";
   public InvalidRedBlackNodeColorException() : base(message) { }

}

public class EntryAlreadyExistsException : Exception {

   static String message = "The set entry already exists.";
   public EntryAlreadyExistsException() : base(message) { }

}

//************************************************************************ //****************************** AVL Sets ******************************** //************************************************************************

public enum State { Header, LeftHigh, Balanced, RightHigh };

public enum SetOperation {

   Union,
   Intersection,
   SymmetricDifference,
   Difference,
   Equality,
   Inequality,
   Subset,
   Superset

}

public class Node {

   public Node Left;
   public Node Right;
   public Node Parent;
   public State Balance;
   public Node()
   {
       Left = this;
       Right = this;
       Parent = null;
       Balance = State.Header;
   }
   public Node(Node p)
   {
       Left = null;
       Right = null;
       Parent = p;
       Balance = State.Balanced;
   }
   public bool IsHeader
   { get { return Balance == State.Header; } }

}

public class SetNode<T> : Node {

   public T Data;
   public SetNode() { }
   public SetNode(T dataType, Node Parent)
       : base(Parent)
   {
       Data = dataType;
   }
   public override int GetHashCode()
   {
       return Data.GetHashCode();
   }

}

class Utility // Nongeneric Tree Balancing {

   static void RotateLeft(ref Node Root)
   {
       Node Parent = Root.Parent;
       Node x = Root.Right;
       Root.Parent = x;
       x.Parent = Parent;
       if (x.Left != null) x.Left.Parent = Root;
       Root.Right = x.Left;
       x.Left = Root;
       Root = x;
   }
   static void RotateRight(ref Node Root)
   {
       Node Parent = Root.Parent;
       Node x = Root.Left;
       Root.Parent = x;
       x.Parent = Parent;
       if (x.Right != null) x.Right.Parent = Root;
       Root.Left = x.Right;
       x.Right = Root;
       Root = x;
   }
   static void BalanceLeft(ref Node Root)
   {
       Node Left = Root.Left;
       switch (Left.Balance)
       {
           case State.LeftHigh:
               Root.Balance = State.Balanced;
               Left.Balance = State.Balanced;
               RotateRight(ref Root);
               break;
           case State.RightHigh:
               {
                   Node subRight = Left.Right;
                   switch (subRight.Balance)
                   {
                       case State.Balanced:
                           Root.Balance = State.Balanced;
                           Left.Balance = State.Balanced;
                           break;
                       case State.RightHigh:
                           Root.Balance = State.Balanced;
                           Left.Balance = State.LeftHigh;
                           break;
                       case State.LeftHigh:
                           Root.Balance = State.RightHigh;
                           Left.Balance = State.Balanced;
                           break;
                   }
                   subRight.Balance = State.Balanced;
                   RotateLeft(ref Left);
                   Root.Left = Left;
                   RotateRight(ref Root);
               }
               break;
           case State.Balanced:
               Root.Balance = State.LeftHigh;
               Left.Balance = State.RightHigh;
               RotateRight(ref Root);
               break;
       }
   }
   static void BalanceRight(ref Node Root)
   {
       Node Right = Root.Right;
       switch (Right.Balance)
       {
           case State.RightHigh:
               Root.Balance = State.Balanced;
               Right.Balance = State.Balanced;
               RotateLeft(ref Root);
               break;
           case State.LeftHigh:
               {
                   Node subLeft = Right.Left; // Left Subtree of Right
                   switch (subLeft.Balance)
                   {
                       case State.Balanced:
                           Root.Balance = State.Balanced;
                           Right.Balance = State.Balanced;
                           break;
                       case State.LeftHigh:
                           Root.Balance = State.Balanced;
                           Right.Balance = State.RightHigh;
                           break;
                       case State.RightHigh:
                           Root.Balance = State.LeftHigh;
                           Right.Balance = State.Balanced;
                           break;
                   }
                   subLeft.Balance = State.Balanced;
                   RotateRight(ref Right);
                   Root.Right = Right;
                   RotateLeft(ref Root);
               }
               break;
           case State.Balanced:
               Root.Balance = State.RightHigh;
               Right.Balance = State.LeftHigh;
               RotateLeft(ref Root);
               break;
       }
   }
   public static void BalanceSet(Node Root, Direction From)
   {
       bool Taller = true;
       while (Taller)
       {
           Node Parent = Root.Parent;
           Direction NextFrom = (Parent.Left == Root) ? Direction.FromLeft : Direction.FromRight;
           if (From == Direction.FromLeft)
           {
               switch (Root.Balance)
               {
                   case State.LeftHigh:
                       if (Parent.IsHeader)
                           BalanceLeft(ref Parent.Parent);
                       else if (Parent.Left == Root)
                           BalanceLeft(ref Parent.Left);
                       else
                           BalanceLeft(ref Parent.Right);
                       Taller = false;
                       break;
                   case State.Balanced:
                       Root.Balance = State.LeftHigh;
                       Taller = true;
                       break;
                   case State.RightHigh:
                       Root.Balance = State.Balanced;
                       Taller = false;
                       break;
               }
           }
           else
           {
               switch (Root.Balance)
               {
                   case State.LeftHigh:
                       Root.Balance = State.Balanced;
                       Taller = false;
                       break;
                   case State.Balanced:
                       Root.Balance = State.RightHigh;
                       Taller = true;
                       break;
                   case State.RightHigh:
                       if (Parent.IsHeader)
                           BalanceRight(ref Parent.Parent);
                       else if (Parent.Left == Root)
                           BalanceRight(ref Parent.Left);
                       else
                           BalanceRight(ref Parent.Right);
                       Taller = false;
                       break;
               }
           }
           if (Taller) // skip up a level
           {
               if (Parent.IsHeader)
                   Taller = false;
               else
               {
                   Root = Parent;
                   From = NextFrom;
               }
           }
       }
   }
   public static void BalanceSetRemove(Node Root, Direction From)
   {
       if (Root.IsHeader) return;
       bool Shorter = true;
       while (Shorter)
       {
           Node Parent = Root.Parent;
           Direction NextFrom = (Parent.Left == Root) ? Direction.FromLeft : Direction.FromRight;
           if (From == Direction.FromLeft)
           {
               switch (Root.Balance)
               {
                   case State.LeftHigh:
                       Root.Balance = State.Balanced;
                       Shorter = true;
                       break;
                   case State.Balanced:
                       Root.Balance = State.RightHigh;
                       Shorter = false;
                       break;
                   case State.RightHigh:
                       if (Root.Right.Balance == State.Balanced)
                           Shorter = false;
                       else
                           Shorter = true;
                       if (Parent.IsHeader)
                           BalanceRight(ref Parent.Parent);
                       else if (Parent.Left == Root)
                           BalanceRight(ref Parent.Left);
                       else
                           BalanceRight(ref Parent.Right);
                       break;
               }
           }
           else
           {
               switch (Root.Balance)
               {
                   case State.RightHigh:
                       Root.Balance = State.Balanced;
                       Shorter = true;
                       break;
                   case State.Balanced:
                       Root.Balance = State.LeftHigh;
                       Shorter = false;
                       break;
                   case State.LeftHigh:
                       if (Root.Left.Balance == State.Balanced)
                           Shorter = false;
                       else
                           Shorter = true;
                       if (Parent.IsHeader)
                           BalanceLeft(ref Parent.Parent);
                       else if (Parent.Left == Root)
                           BalanceLeft(ref Parent.Left);
                       else
                           BalanceLeft(ref Parent.Right);
                       break;
               }
           }
           if (Shorter)
           {
               if (Parent.IsHeader)
                   Shorter = false;
               else
               {
                   From = NextFrom;
                   Root = Parent;
               }
           }
       }
   }
   public static Node PreviousItem(Node Node)
   {
       if (Node.IsHeader) { return Node.Right; }
       if (Node.Left != null)
       {
           Node = Node.Left;
           while (Node.Right != null) Node = Node.Right;
       }
       else
       {
           Node y = Node.Parent;
           if (y.IsHeader) return y;
           while (Node == y.Left) { Node = y; y = y.Parent; }
           Node = y;
       }
       return Node;
   }
   public static Node NextItem(Node Node)
   {
       if (Node.IsHeader) return Node.Left;
       if (Node.Right != null)
       {
           Node = Node.Right;
           while (Node.Left != null) Node = Node.Left;
       }
       else
       {
           Node y = Node.Parent;
           if (y.IsHeader) return y;
           while (Node == y.Right) { Node = y; y = y.Parent; }
           Node = y;
       }
       return Node;
   }
   public static ulong Depth(Node Root)
   {
       if (Root != null)
       {
           ulong Left = Root.Left != null ? Depth(Root.Left) : 0;
           ulong Right = Root.Right != null ? Depth(Root.Right) : 0;
           return Left < Right ? Right + 1 : Left + 1;
       }
       else
           return 0;
   }
   static void SwapNodeReference(ref Node First,
                                 ref Node Second)
   { Node Temporary = First; First = Second; Second = Temporary; }
   public static void SwapNodes(Node A, Node B)
   {
       if (B == A.Left)
       {
           if (B.Left != null) B.Left.Parent = A;
           if (B.Right != null) B.Right.Parent = A;
           if (A.Right != null) A.Right.Parent = B;
           if (!A.Parent.IsHeader)
           {
               if (A.Parent.Left == A)
                   A.Parent.Left = B;
               else
                   A.Parent.Right = B;
           }
           else A.Parent.Parent = B;
           B.Parent = A.Parent;
           A.Parent = B;
           A.Left = B.Left;
           B.Left = A;
           SwapNodeReference(ref A.Right, ref B.Right);
       }
       else if (B == A.Right)
       {
           if (B.Right != null) B.Right.Parent = A;
           if (B.Left != null) B.Left.Parent = A;
           if (A.Left != null) A.Left.Parent = B;
           if (!A.Parent.IsHeader)
           {
               if (A.Parent.Left == A)
                   A.Parent.Left = B;
               else
                   A.Parent.Right = B;
           }
           else A.Parent.Parent = B;
           B.Parent = A.Parent;
           A.Parent = B;
           A.Right = B.Right;
           B.Right = A;
           SwapNodeReference(ref A.Left, ref B.Left);
       }
       else if (A == B.Left)
       {
           if (A.Left != null) A.Left.Parent = B;
           if (A.Right != null) A.Right.Parent = B;
           if (B.Right != null) B.Right.Parent = A;
           if (!B.Parent.IsHeader)
           {
               if (B.Parent.Left == B)
                   B.Parent.Left = A;
               else
                   B.Parent.Right = A;
           }
           else B.Parent.Parent = A;
           A.Parent = B.Parent;
           B.Parent = A;
           B.Left = A.Left;
           A.Left = B;
           SwapNodeReference(ref A.Right, ref B.Right);
       }
       else if (A == B.Right)
       {
           if (A.Right != null) A.Right.Parent = B;
           if (A.Left != null) A.Left.Parent = B;
           if (B.Left != null) B.Left.Parent = A;
           if (!B.Parent.IsHeader)
           {
               if (B.Parent.Left == B)
                   B.Parent.Left = A;
               else
                   B.Parent.Right = A;
           }
           else B.Parent.Parent = A;
           A.Parent = B.Parent;
           B.Parent = A;
           B.Right = A.Right;
           A.Right = B;
           SwapNodeReference(ref A.Left, ref B.Left);
       }
       else
       {
           if (A.Parent == B.Parent)
               SwapNodeReference(ref A.Parent.Left, ref A.Parent.Right);
           else
           {
               if (!A.Parent.IsHeader)
               {
                   if (A.Parent.Left == A)
                       A.Parent.Left = B;
                   else
                       A.Parent.Right = B;
               }
               else A.Parent.Parent = B;
               if (!B.Parent.IsHeader)
               {
                   if (B.Parent.Left == B)
                       B.Parent.Left = A;
                   else
                       B.Parent.Right = A;
               }
               else B.Parent.Parent = A;
           }
           if (B.Left != null) B.Left.Parent = A;
           if (B.Right != null) B.Right.Parent = A;
           if (A.Left != null) A.Left.Parent = B;
           if (A.Right != null) A.Right.Parent = B;
           SwapNodeReference(ref A.Left, ref B.Left);
           SwapNodeReference(ref A.Right, ref B.Right);
           SwapNodeReference(ref A.Parent, ref B.Parent);
       }
       State Balance = A.Balance;
       A.Balance = B.Balance;
       B.Balance = Balance;
   }

}

public struct SetEntry<T> : IEnumerator<T> {

   public SetEntry(Node N) { _Node = N; }
   public T Value
   {
       get
       {
           return ((SetNode<T>)_Node).Data;
       }
   }
   public bool IsEnd { get { return _Node.IsHeader; } }
   public bool MoveNext()
   {
       _Node = Utility.NextItem(_Node);
       return _Node.IsHeader ? false : true;
   }
   public bool MovePrevious()
   {
       _Node = Utility.PreviousItem(_Node);
       return _Node.IsHeader ? false : true;
   }
   public static SetEntry<T> operator ++(SetEntry<T> entry)
   {
       entry._Node = Utility.NextItem(entry._Node);
       return entry;
   }
   public static SetEntry<T> operator --(SetEntry<T> entry)
   {
       entry._Node = Utility.PreviousItem(entry._Node);
       return entry;
   }
   public void Reset()
   {
       while (!MoveNext()) ;
   }
   object System.Collections.IEnumerator.Current
   { get { return ((SetNode<T>)_Node).Data; } }
   T IEnumerator<T>.Current
   { get { return ((SetNode<T>)_Node).Data; } }
   public static bool operator ==(SetEntry<T> x, SetEntry<T> y) { return x._Node == y._Node; }
   public static bool operator !=(SetEntry<T> x, SetEntry<T> y) { return x._Node != y._Node; }
   public override bool Equals(object o) { return _Node == ((SetEntry<T>)o)._Node; }
   public override int GetHashCode() { return _Node.GetHashCode(); }
   public static SetEntry<T> operator +(SetEntry<T> C, ulong Increment)
   {
       SetEntry<T> Result = new SetEntry<T>(C._Node);
       for (ulong i = 0; i < Increment; i++) ++Result;
       return Result;
   }
   public static SetEntry<T> operator +(ulong Increment, SetEntry<T> C)
   {
       SetEntry<T> Result = new SetEntry<T>(C._Node);
       for (ulong i = 0; i < Increment; i++) ++Result;
       return Result;
   }
   public static SetEntry<T> operator -(SetEntry<T> C, ulong Decrement)
   {
       SetEntry<T> Result = new SetEntry<T>(C._Node);
       for (ulong i = 0; i < Decrement; i++) --Result;
       return Result;
   }
   public override string ToString()
   {
       return Value.ToString();
   }
   public void Dispose() { }
   public Node _Node;

}

class Set<T> : IEnumerable<T> {

   IComparer<T> Comparer;
   Node Header;
   ulong Nodes;
   //*** Constructors ***
   public Set()
   {
       Comparer = Comparer<T>.Default;
       Header = new Node();
       Nodes = 0;
   }
   public Set(IComparer<T> c)
   {
       Comparer = c;
       Header = new Node();
       Nodes = 0;
   }
   //*** Properties ***
   SetNode<T> Root
   {
       get { return (SetNode<T>)Header.Parent; }
       set { Header.Parent = value; }
   }
   Node LeftMost
   {
       get { return Header.Left; }
       set { Header.Left = value; }
   }
   Node RightMost
   {
       get { return Header.Right; }
       set { Header.Right = value; }
   }
   public SetEntry<T> Begin
   { get { return new SetEntry<T>(Header.Left); } }
   public SetEntry<T> End
   { get { return new SetEntry<T>(Header); } }
   public ulong Length { get { return Nodes; } }
   public ulong Depth { get { return Utility.Depth(Root); } }
   //*** Operators ***
   public bool this[T key] { get { return Search(key); } }
   public static Set<T> operator +(Set<T> set, T t)
   {
       set.Add(t); return set;
   }
   public static Set<T> operator -(Set<T> set, T t)
   {
       set.Remove(t); return set;
   }
   public static Set<T> operator |(Set<T> A, Set<T> B)
   {
       Set<T> U = new Set<T>(A.Comparer);
       CombineSets(A, B, U, SetOperation.Union);
       return U;
   }
   public static Set<T> operator &(Set<T> A, Set<T> B)
   {
       Set<T> I = new Set<T>(A.Comparer);
       CombineSets(A, B, I, SetOperation.Intersection);
       return I;
   }
   public static Set<T> operator ^(Set<T> A, Set<T> B)
   {
       Set<T> S = new Set<T>(A.Comparer);
       CombineSets(A, B, S, SetOperation.SymmetricDifference);
       return S;
   }
   public static Set<T> operator -(Set<T> A, Set<T> B)
   {
       Set<T> S = new Set<T>(A.Comparer);
       CombineSets(A, B, S, SetOperation.Difference);
       return S;
   }
   public static bool operator ==(Set<T> A, Set<T> B)
   {
       return CheckSets(A, B, SetOperation.Equality);
   }
   public static bool operator !=(Set<T> A, Set<T> B)
   {
       return CheckSets(A, B, SetOperation.Inequality);
   }
   public override bool Equals(object o)
   {
       return CheckSets(this, (Set<T>)o, SetOperation.Equality);
   }


   //*** Methods ***
   public void Add(T key)
   {
       if (Root == null)
       {
           Root = new SetNode<T>(key, Header);
           LeftMost = RightMost = Root;
       }
       else
       {
           SetNode<T> Search = Root;
           for (; ; )
           {
               int Compare = Comparer.Compare(key, Search.Data);
               if (Compare == 0) // Item Exists
                   throw new EntryAlreadyExistsException();
               else if (Compare < 0)
               {
                   if (Search.Left != null)
                       Search = (SetNode<T>)Search.Left;
                   else
                   {
                       Search.Left = new SetNode<T>(key, Search);
                       if (LeftMost == Search) LeftMost = (SetNode<T>)Search.Left;
                       Utility.BalanceSet(Search, Direction.FromLeft);
                       Nodes++;
                   }
               }
               else
               {
                   if (Search.Right != null)
                       Search = (SetNode<T>)Search.Right;
                   else
                   {
                       Search.Right = new SetNode<T>(key, Search);
                       if (RightMost == Search) RightMost = (SetNode<T>)Search.Right;
                       Utility.BalanceSet(Search, Direction.FromRight);
                       Nodes++;
                       break;
                   }
               }
           }
       }
   }
   System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
   { return new SetEntry<T>(Header); }
   IEnumerator<T> IEnumerable<T>.GetEnumerator()
   { return new SetEntry<T>(Header); }
   public override int GetHashCode()
   {
       return GetHashCode((SetNode<T>)Header.Parent);
   }
   int GetHashCode(SetNode<T> Root)
   {
       if (Root != null)
       {
           int HashCode = Root.GetHashCode();
           if (Root.Left != null)
               HashCode += GetHashCode((SetNode<T>)Root.Left);
           if (Root.Right != null)
               HashCode += GetHashCode((SetNode<T>)Root.Right);
           return HashCode;
       }
       return 0;
   }


   public void Remove(T key)
   {
       SetNode<T> root = Root;
       for (; ; )
       {
           if (root == null)
               throw new EntryNotFoundException();
           int Compare = Comparer.Compare(key, root.Data);
           if (Compare < 0)
               root = (SetNode<T>)root.Left;
           else if (Compare > 0)
               root = (SetNode<T>)root.Right;
           else // Item is found
           {
               if (root.Left != null && root.Right != null)
               {
                   SetNode<T> replace = (SetNode<T>)root.Left;
                   while (replace.Right != null) replace = (SetNode<T>)replace.Right;
                   Utility.SwapNodes(root, replace);
               }
               SetNode<T> Parent = (SetNode<T>)root.Parent;
               Direction From = (Parent.Left == root) ? Direction.FromLeft : Direction.FromRight;
               if (LeftMost == root)
               {
                   SetEntry<T> e = new SetEntry<T>(root); e.MoveNext();
                   if (e._Node.IsHeader)
                   { LeftMost = Header; RightMost = Header; }
                   else
                       LeftMost = e._Node;
               }
               else if (RightMost == root)
               {
                   SetEntry<T> e = new SetEntry<T>(root); e.MovePrevious();
                   if (e._Node.IsHeader)
                   { LeftMost = Header; RightMost = Header; }
                   else
                       RightMost = e._Node;
               }
               if (root.Left == null)
               {
                   if (Parent == Header)
                       Header.Parent = root.Right;
                   else if (Parent.Left == root)
                       Parent.Left = root.Right;
                   else
                       Parent.Right = root.Right;
                   if (root.Right != null) root.Right.Parent = Parent;
               }
               else
               {
                   if (Parent == Header)
                       Header.Parent = root.Left;
                   else if (Parent.Left == root)
                       Parent.Left = root.Left;
                   else
                       Parent.Right = root.Left;
                   if (root.Left != null) root.Left.Parent = Parent;
               }
               Utility.BalanceSetRemove(Parent, From);
               Nodes--;
               break;
           }
       }
   }
   public bool Search(T key)
   {
       if (Root == null)
           return false;
       else
       {
           SetNode<T> Search = Root;
           do
           {
               int Result = Comparer.Compare(key, Search.Data);
               if (Result < 0) Search = (SetNode<T>)Search.Left;
               else if (Result > 0) Search = (SetNode<T>)Search.Right;
               else break;
           } while (Search != null);
           if (Search == null)
               return false;
           else
               return true;
       }
   }
   public override string ToString()
   {
       string StringOut = "{";
       SetEntry<T> start = Begin;
       SetEntry<T> end = End;
       SetEntry<T> last = End - 1;
       while (start != end)
       {
           string new_StringOut = start.Value.ToString();
           if (start != last) new_StringOut = new_StringOut + ",";
           StringOut = StringOut + new_StringOut;
           ++start;
       }
       StringOut = StringOut + "}";
       return StringOut;
   }
   public void Validate()
   {
       if (Nodes == 0 || Root == null)
       {
           if (Nodes != 0) { throw new InvalidEmptyTreeException(); }
           if (Root != null) { throw new InvalidEmptyTreeException(); }
           if (LeftMost != Header) { throw new InvalidEndItemException(); }
           if (RightMost != Header) { throw new InvalidEndItemException(); }
       }
       Validate(Root);
       if (Root != null)
       {
           SetNode<T> x = Root;
           while (x.Left != null) x = (SetNode<T>)x.Left;
           if (LeftMost != x) throw new InvalidEndItemException();
           SetNode<T> y = Root;
           while (y.Right != null) y = (SetNode<T>)y.Right;
           if (RightMost != y) throw new InvalidEndItemException();
       }
   }
   void Validate(SetNode<T> root)
   {
       if (root == null) return;
       if (root.Left != null)
       {
           SetNode<T> Left = (SetNode<T>)root.Left;
           if (Comparer.Compare(Left.Data, root.Data) >= 0)
               throw new OutOfKeyOrderException();
           if (Left.Parent != root)
               throw new TreeInvalidParentException();
           Validate((SetNode<T>)root.Left);
       }
       if (root.Right != null)
       {
           SetNode<T> Right = (SetNode<T>)root.Right;
           if (Comparer.Compare(Right.Data, root.Data) <= 0)
               throw new OutOfKeyOrderException();
           if (Right.Parent != root)
               throw new TreeInvalidParentException();
           Validate((SetNode<T>)root.Right);
       }
       ulong depth_Left = root.Left != null ? Utility.Depth(root.Left) : 0;
       ulong depth_Right = root.Right != null ? Utility.Depth(root.Right) : 0;
       if (depth_Left > depth_Right && depth_Left - depth_Right > 2)
           throw new TreeOutOfBalanceException();
       if (depth_Left < depth_Right && depth_Right - depth_Left > 2)
           throw new TreeOutOfBalanceException();
   }
   public static void CombineSets(Set<T> A,
                                  Set<T> B,
                                  Set<T> R,
                                  SetOperation operation)
   {
       IComparer<T> TComparer = R.Comparer;
       SetEntry<T> First1 = A.Begin;
       SetEntry<T> Last1 = A.End;
       SetEntry<T> First2 = B.Begin;
       SetEntry<T> Last2 = B.End;
       switch (operation)
       {
           case SetOperation.Union:
               while (First1 != Last1 && First2 != Last2)
               {
                   int Order = TComparer.Compare(First1.Value, First2.Value);
                   if (Order < 0)
                   {
                       R.Add(First1.Value);
                       First1.MoveNext();
                   }
                   else if (Order > 0)
                   {
                       R.Add(First2.Value);
                       First2.MoveNext();
                   }
                   else
                   {
                       R.Add(First1.Value);
                       First1.MoveNext();
                       First2.MoveNext();
                   }
               }
               while (First1 != Last1)
               {
                   R.Add(First1.Value);
                   First1.MoveNext();
               }
               while (First2 != Last2)
               {
                   R.Add(First2.Value);
                   First2.MoveNext();
               }
               return;
           case SetOperation.Intersection:
               while (First1 != Last1 && First2 != Last2)
               {
                   int Order = TComparer.Compare(First1.Value, First2.Value);
                   if (Order < 0)
                       First1.MoveNext();
                   else if (Order > 0)
                       First2.MoveNext();
                   else
                   {
                       R.Add(First1.Value);
                       First1.MoveNext();
                       First2.MoveNext();
                   }
               }
               return;
           case SetOperation.SymmetricDifference:
               while (First1 != Last1 && First2 != Last2)
               {
                   int Order = TComparer.Compare(First1.Value, First2.Value);
                   if (Order < 0)
                   {
                       R.Add(First1.Value);
                       First1.MoveNext();
                   }
                   else if (Order > 0)
                   {
                       R.Add(First2.Value);
                       First2.MoveNext();
                   }
                   else
                   { First1.MoveNext(); First2.MoveNext(); }
               }
               while (First1 != Last1)
               {
                   R.Add(First1.Value);
                   First1.MoveNext();
               }
               while (First2 != Last2)
               {
                   R.Add(First2.Value);
                   First2.MoveNext();
               }
               return;
           case SetOperation.Difference:
               while (First1 != Last1 && First2 != Last2)
               {
                   int Order = TComparer.Compare(First1.Value, First2.Value);
                   if (Order < 0)
                   {
                       R.Add(First1.Value);
                       First1.MoveNext();
                   }
                   else if (Order > 0)
                   {
                       R.Add(First1.Value);
                       First1.MoveNext();
                       First2.MoveNext();
                   }
                   else
                   { First1.MoveNext(); First2.MoveNext(); }
               }
               while (First1 != Last1)
               {
                   R.Add(First1.Value);
                   First1.MoveNext();
               }
               return;
       }
       throw new InvalidSetOperationException();
   }
   public static bool CheckSets(Set<T> A,
                                Set<T> B,
                                SetOperation operation)
   {
       IComparer<T> TComparer = A.Comparer;
       SetEntry<T> First1 = A.Begin;
       SetEntry<T> Last1 = A.End;
       SetEntry<T> First2 = B.Begin;
       SetEntry<T> Last2 = B.End;
       switch (operation)
       {
           case SetOperation.Equality:
           case SetOperation.Inequality:
               {
                   bool Equals = true;
                   while (First1 != Last1 && First2 != Last2)
                   {
                       if (TComparer.Compare(First1.Value, First2.Value) == 0)
                       { First1.MoveNext(); First2.MoveNext(); }
                       else
                       { Equals = false; break; }
                   }
                   if (Equals)
                   {
                       if (First1 != Last1) Equals = false;
                       if (First2 != Last2) Equals = false;
                   }
                   if (operation == SetOperation.Equality)
                       return Equals;
                   else
                       return !Equals;
               }
           case SetOperation.Subset:
           case SetOperation.Superset:
               {
                   bool Subset = true;
                   while (First1 != Last1 && First2 != Last2)
                   {
                       int Order = TComparer.Compare(First1.Value, First2.Value);
                       if (Order < 0)
                       { Subset = false; break; }
                       else if (Order > 0)
                           First2.MoveNext();
                       else
                       { First1.MoveNext(); First2.MoveNext(); }
                   }
                   if (Subset)
                       if (First1 != Last1) Subset = false;
                   if (operation == SetOperation.Subset)
                       return Subset;
                   else
                       return !Subset;
               }
       }
       throw new InvalidSetOperationException();
   }

}


public class InvalidEmptyTreeException : Exception {

   static String message = "The validation routines detected that an empty tree is invalid.";
   public InvalidEmptyTreeException() : base(message) { }

}

public class TreeInvalidParentException : Exception {

   static String message = "The validation routines detected that the Parent structure of a tree is invalid.";
   public TreeInvalidParentException() : base(message) { }

}

public class TreeOutOfBalanceException : Exception {

   static String message = "The validation routines detected that the tree is out of State.";
   public TreeOutOfBalanceException() : base(message) { }

}

public class InvalidSetOperationException : Exception {

   static String message = "An invalid set operation was requested.";
   public InvalidSetOperationException() : base(message) { }

}

enum Limits { Maximum = 100000 };

class Program {

   static void Main()
   {
       //*** First Red/Black Timings ***
       RedBlackSet<int> R = new RedBlackSet<int>();
       DateTime BuildRedBlackStart = DateTime.Now;
       for (int i = 0; i < (int)Limits.Maximum; i++)
           R.Add(i);
       DateTime BuildRedBlackEnd = DateTime.Now;
       Console.WriteLine("Red/Black Build Time = {0}", BuildRedBlackEnd - BuildRedBlackStart);
       DateTime SearchRedBlackStart = DateTime.Now;
       for (int i = 0; i < (int)Limits.Maximum; i++)
       {
           bool inRedBlackSet = R[i];
       }
       DateTime SearchRedBlackEnd = DateTime.Now;
       Console.WriteLine("Red/Black Search Time = {0}", SearchRedBlackEnd - SearchRedBlackStart);
       //*** Now AVL Timings ***
       Set<int> A = new Set<int>();
       DateTime BuildAVLStart = DateTime.Now;
       for (int i = 0; i < (int)Limits.Maximum; i++)
           A.Add(i);
       DateTime BuildAVLEnd = DateTime.Now;
       Console.WriteLine("AVL Build Time = {0}", BuildAVLEnd - BuildAVLStart);
       DateTime SearchAVLStart = DateTime.Now;
       for (int i = 0; i < (int)Limits.Maximum; i++)
       {
           bool inAVLSet = A[i];
       }
       DateTime SearchAVLEnd = DateTime.Now;
       Console.WriteLine("AVL Search Time = {0}", SearchAVLEnd - SearchAVLStart);
   }

} </lang>

The results were as follows.

Red/Black Build Time = 00:00:00.0469217
Red/Black Search Time = 00:00:00.0156213
AVL Build Time = 00:00:00.0312380
AVL Search Time = 00:00:00.0156456

The times for build are a suprise - AVL is faster to build than red/black. This is contrary to popular belief. The search times being roughly equal is expected.