/// <summary>
 /// Function that balance the tree after having updated its height
 /// </summary>
 /// <param name="node">the root of the tree to balance </param>
 private void Balance(ref AvlTreeNode <T> node)
 {
     // Left Heavy Tree
     if (GetBalanceFactor(node) == 2)
     {
         if (GetBalanceFactor(node.Left) > -1)                 // Left Heavy Left Subtree or zero balance factor
         {
             SingleRightRotation(ref node);
         }
         else                 // Right Heavy Left Subtree
         {
             DoubleLeftRightRotation(ref node);
         }
     }             // Right Heavy Tree
     else if (GetBalanceFactor(node) == -2)
     {
         if (GetBalanceFactor(node.Right) < 1)                 // Right Heavy Right Subtree or zero balance factor
         {
             SingleLeftRotation(ref node);
         }
         else                 // Left Heavy Right SubTree
         {
             DoubleRightLeftRotation(ref node);
         }
     }
 }
 /// <summary>
 /// Get the maximum value of a tree
 /// </summary>
 /// <param name="avlTreeNode">the root of the tree</param>
 /// <returns>the maximum value of the tree</returns>
 private static T FindMaxValue(AvlTreeNode <T> avlTreeNode)
 {
     while (avlTreeNode.Right != null)
     {
         avlTreeNode = avlTreeNode.Right;
     }
     return(avlTreeNode.Value);
 }
        /// <summary>
        /// A Single rotation composed of a left rotation and a right rotation.
        /// </summary>
        /// <param name="node">The pivoting node involved in rotations.</param>
        private void SingleRightRotation(ref AvlTreeNode <T> node)
        {
            AvlTreeNode <T> node1 = node.Left;

            node.Left   = node1.Right;
            node1.Right = node;
            AdjustHeight(node);
            AdjustHeight(node1);
            node = node1;
        }
 /// <summary>
 /// Inserts a new node with the specified value at the appropriate location in the <see cref="AvlTree{T}"/>.
 /// </summary>
 /// <remarks>
 /// This method is an O(log n) operation plus constant time due to rebalancing.
 /// </remarks>
 /// <param name="item">Value to insert.</param>
 public override void Add(T item)
 {
     if (Root == null)
     {
         Root = new AvlTreeNode <T>(item);
     }
     else
     {
         AvlTreeNode <T> root = Root;
         InsertNode(ref root, item, true);
         Root = root;
     }
     Count++;
 }
        /// <summary>
        /// Called by the Add method. Finds the location where to put the node in the <see cref="AvlTree{T}"/> and if
        /// necessary rebalance.
        /// </summary>
        /// <param name="avlNode">Node to start searching from.</param>
        /// <param name="value">Value to insert into the tree.</param>
        /// <param name="insertDuplicates">if set to <c>true</c>, inserts value if it is a duplicate.</param>
        /// <returns><c>true</c> if a new node was added, <c>false</c> otherwise</returns>
        private bool InsertNode(ref AvlTreeNode <T> avlNode, T value, bool insertDuplicates)
        {
            int compareResult = Comparer.Compare(value, avlNode.Value);

            if (!insertDuplicates && (compareResult == 0))
            {
                return(false);
            }

            bool newNodeAdded = true;

            if (compareResult < 0)
            {
                if (avlNode.Left == null)
                {
                    avlNode.Left = new AvlTreeNode <T>(value);
                }
                else
                {
                    AvlTreeNode <T> left = avlNode.Left;
                    newNodeAdded = InsertNode(ref left, value, insertDuplicates);
                    avlNode.Left = left;
                }
            }
            else
            {
                if (avlNode.Right == null)
                {
                    avlNode.Right = new AvlTreeNode <T>(value);
                }
                else
                {
                    AvlTreeNode <T> right = avlNode.Right;
                    newNodeAdded  = InsertNode(ref right, value, insertDuplicates);
                    avlNode.Right = right;
                }
            }
            if (newNodeAdded)
            {
                if ((GetBalanceFactor(avlNode) == 2) || (GetBalanceFactor(avlNode) == -2))
                {
                    Balance(ref avlNode);
                }
                else
                {
                    AdjustHeight(avlNode);
                }
            }
            return(newNodeAdded);
        }
        /// <summary>
        /// Called by remove public method. This removal helper method find the item to
        /// remove and if present remove it rebalancing in case the avl tree
        /// </summary>
        /// <param name="avlNode">root subtree node to start deleting </param>
        /// <param name="item">value to delete</param>
        /// <returns>the root of the tree with value removed</returns>
        private AvlTreeNode <T> RemoveNode(AvlTreeNode <T> avlNode, T item)
        {
            if (avlNode == null)
            {
                throw new Exception("item not found");
            }
            if (item.IsLessThan(avlNode.Value, Comparer))
            {
                avlNode.Left = RemoveNode(avlNode.Left, item);
            }
            else if (item.IsGreaterThan(avlNode.Value, Comparer))
            {
                avlNode.Right = RemoveNode(avlNode.Right, item);
            }
            else if (item.IsEqual(avlNode.Value, Comparer))
            {
                if (avlNode.Right == null && avlNode.Left == null)
                {
                    // node to remove is a leaf, we simply delete node
                    return(null);
                }
                if (avlNode.Left == null)
                {
                    // node to remove has only a right subtree, we link it with its parent
                    return(avlNode.Right);
                }
                if (avlNode.Right == null)
                {
                    // node to remove has only a left subtree, we link it with its parent
                    return(avlNode.Left);
                }
                // node to remove has both childs
                T newValue = FindMaxValue(avlNode.Left);
                avlNode.Value = newValue;
                avlNode.Left  = RemoveNode(avlNode.Left, newValue);
            }
            // Checking for unbalance, if detected, balance (include also height update)
            // otherwise only Adjust height
            if ((GetBalanceFactor(avlNode) == 2) || (GetBalanceFactor(avlNode) == -2))
            {
                Balance(ref avlNode);
            }
            else
            {
                AdjustHeight(avlNode);
            }

            return(avlNode);
        }
        /// <summary>
        /// A Double rotation composed of a right rotation and a left rotation.
        /// </summary>
        /// <param name="node">The pivoting node involved in rotations.</param>
        private void DoubleRightLeftRotation(ref AvlTreeNode <T> node)
        {
            AvlTreeNode <T> node1 = node.Right.Left;

            node.Right.Left = node1.Right;
            node1.Right     = node.Right;
            AdjustHeight(node.Right);
            AdjustHeight(node1);

            node.Right = node1.Left;
            node1.Left = node;
            AdjustHeight(node);
            AdjustHeight(node1);
            node = node1;
        }
        /// <summary>
        /// Inserts a new node with the specified value at the appropriate location in the <see cref="AvlTree{T}"/>
        /// if it does not already exist within the tree. Does nothing otherwise.
        /// </summary>
        /// <remarks>
        /// This method is an O(log n) operation plus constant time due to rebalancing.
        /// </remarks>
        /// <param name="item">The item.</param>
        /// <returns>true if node was unique and added.</returns>
        public bool AddUnique(T item)
        {
            if (Root == null)
            {
                Root = new AvlTreeNode <T>(item);
                Count++;
                return(true);
            }
            AvlTreeNode <T> root         = Root;
            bool            newNodeAdded = InsertNode(ref root, item, false);

            Root = root;
            if (newNodeAdded)
            {
                Count++;
            }
            return(newNodeAdded);
        }
 /// <summary>
 /// Set the proper height of a node
 /// </summary>
 /// <param name="avlNode">the node needing a height fix </param>
 private void AdjustHeight(AvlTreeNode <T> avlNode)
 {
     avlNode.Height = Math.Max(Height(avlNode.Left), Height(avlNode.Right)) + 1;
 }
 /// <summary>
 /// Retrieves the height of the specified node.
 /// </summary>
 /// <param name="node">Node to obtain depth.</param>
 /// <returns>If the node is null 0; otherwise its proper height.</returns>
 public int Height(AvlTreeNode <T> node)
 {
     return((node == null) ? 0 : node.Height);
 }
 /// <summary>
 /// Get the balance factor for the node
 /// Balance factor is defined as the height difference
 /// between left and right subtree if subtrees exist otherwise
 /// for a null node as 0
 /// </summary>
 public int GetBalanceFactor(AvlTreeNode <T> node)
 {
     return((node == null) ? 0 : Height(node.Left) - Height(node.Right));
 }