/// <summary>
        /// Try to remove the key, and return the resulting Dict
        /// if the key is not found, old_node is Empty, else old_node is the Dict
        /// with matching Key
        /// </summary>
        public AvlNode <T> RemoveFromNew(T val, Comparison <T> comparer, out AvlNode <T> old_node)
        {
            if (IsEmpty)
            {
                old_node = Empty;
                return(Empty);
            }
            int comp = comparer(Value, val);

            if (comp < 0)
            {
                var newgt = right.RemoveFromNew(val, comparer, out old_node);
                if (old_node.IsEmpty)
                {
                    //Not found, so nothing changed
                    return(this);
                }
                var newroot = new AvlNode <T> (Value, left, newgt);
                return(newroot.FixRootBalance());
            }
            if (comp > 0)
            {
                var newlt = left.RemoveFromNew(val, comparer, out old_node);
                if (old_node.IsEmpty)
                {
                    //Not found, so nothing changed
                    return(this);
                }
                var newroot = new AvlNode <T> (Value, newlt, right);
                return(newroot.FixRootBalance());
            }
            //found it
            old_node = this;
            return(RemoveRoot());
        }
 /// <summary>
 /// Return a new dict with the root key-value pair removed
 /// </summary>
 AvlNode <T> RemoveRoot()
 {
     if (IsEmpty)
     {
         return(this);
     }
     if (left.IsEmpty)
     {
         return(right);
     }
     if (right.IsEmpty)
     {
         return(left);
     }
     //Neither are empty:
     if (left._count < right._count)
     {
         //LTDict has fewer, so promote from GTDict to minimize depth
         AvlNode <T> min;
         var         newgt   = right.RemoveMin(out min);
         var         newroot = new AvlNode <T> (min.Value, left, newgt);
         return(newroot.FixRootBalance());
     }
     else
     {
         AvlNode <T> max;
         var         newlt   = left.RemoveMax(out max);
         var         newroot = new AvlNode <T> (max.Value, newlt, right);
         return(newroot.FixRootBalance());
     }
 }
        /// <summary>
        /// Return a new tree with the key-value pair inserted
        /// If the key is already present, it replaces the value
        /// This operation is O(Log N) where N is the number of keys
        /// </summary>
        public AvlNode <T> InsertIntoNew(T val, Comparison <T> comparer)
        {
            if (IsEmpty)
            {
                return(new AvlNode <T> (val));
            }

            AvlNode <T> newlt = left;
            AvlNode <T> newgt = right;

            int comp = comparer(Value, val);
            T   newv = Value;

            if (comp < 0)
            {
                //Let the GTDict put it in:
                newgt = right.InsertIntoNew(val, comparer);
            }
            else if (comp > 0)
            {
                //Let the LTDict put it in:
                newlt = left.InsertIntoNew(val, comparer);
            }
            else
            {
                //Replace the current value:
                newv = val;
            }
            var newroot = new AvlNode <T> (newv, newlt, newgt);

            return(newroot.FixRootBalance());
        }
        AvlNode <T> RemoveMin(out AvlNode <T> min)
        {
            if (IsEmpty)
            {
                min = Empty;
                return(Empty);
            }
            if (left.IsEmpty)
            {
                //We are the minimum:
                min = this;
                return(right);
            }
            //Go down:
            var newlt   = left.RemoveMin(out min);
            var newroot = new AvlNode <T> (Value, newlt, right);

            return(newroot.FixRootBalance());
        }
 AvlNode <T> RemoveMax(out AvlNode <T> max)
 {
     if (IsEmpty)
     {
         max = Empty;
         return(Empty);
     }
     if (right.IsEmpty)
     {
         //We are the max:
         max = this;
         return(left);
     }
     else
     {
         //Go down:
         var newgt   = right.RemoveMax(out max);
         var newroot = new AvlNode <T> (Value, left, newgt);
         return(newroot.FixRootBalance());
     }
 }
        /// <summary>
        /// Return a new tree with the key-value pair inserted
        /// If the key is already present, it replaces the value
        /// This operation is O(Log N) where N is the number of keys
        /// </summary>
        public AvlNode <T> InsertIntoNew(int index, T val)
        {
            if (IsEmpty)
            {
                return(new AvlNode <T> (val));
            }

            AvlNode <T> newlt = left;
            AvlNode <T> newgt = right;

            if (index <= left._count)
            {
                newlt = left.InsertIntoNew(index, val);
            }
            else
            {
                newgt = right.InsertIntoNew(index - left._count - 1, val);
            }

            var newroot = new AvlNode <T> (Value, newlt, newgt);

            return(newroot.FixRootBalance());
        }
        /// <summary>
        /// Try to remove the key, and return the resulting Dict
        /// if the key is not found, old_node is Empty, else old_node is the Dict
        /// with matching Key
        /// </summary>
        public AvlNode <T> RemoveFromNew(int index, out AvlNode <T> old_node)
        {
            if (IsEmpty)
            {
                old_node = Empty;
                return(Empty);
            }

            if (index < left._count)
            {
                var newlt = left.RemoveFromNew(index, out old_node);
                if (old_node.IsEmpty)
                {
                    //Not found, so nothing changed
                    return(this);
                }
                var newroot = new AvlNode <T> (Value, newlt, right);
                return(newroot.FixRootBalance());
            }

            if (index > left._count)
            {
                var newgt = right.RemoveFromNew(index - left._count - 1, out old_node);
                if (old_node.IsEmpty)
                {
                    //Not found, so nothing changed
                    return(this);
                }
                var newroot = new AvlNode <T> (Value, left, newgt);
                return(newroot.FixRootBalance());
            }

            //found it
            old_node = this;
            return(RemoveRoot());
        }