private static AvlTreeNode BalanceTree(AvlTreeNode node, int value)
        {
            var balance = GetBalance(node);

            // Left left case
            if (balance > 1 && value < node.Left.Value)
            {
                return(RightRotate(node));
            }

            // Right right case
            if (balance < -1 && value > node.Right.Value)
            {
                return(LeftRotate(node));
            }

            // Left right case
            if (balance > 1 && value > node.Left.Value)
            {
                node.Left = LeftRotate(node.Left);
                return(RightRotate(node));
            }

            // Right left  case
            if (balance < -1 && value < node.Right.Value)
            {
                node.Right = RightRotate(node.Right);
                return(LeftRotate(node));
            }

            return(node);
        }
        public AvlTreeNode Insert(AvlTreeNode node, int key)
        {
            /* 1. Perform the normal BST insertion */
            if (node == null)
            {
                return(new AvlTreeNode(key));
            }

            if (key < node.Value)
            {
                node.Left = Insert(node.Left, key);
            }
            else if (key > node.Value)
            {
                node.Right = Insert(node.Right, key);
            }
            else // Duplicate keys not allowed
            {
                return(node);
            }

            /* 2. Update height of this ancestor node */
            IncreaseHeight(node);
            return(BalanceTree(node, key));
        }
        /* Given a non-empty binary search tree, return the
         * node with minimum key value found in that tree.
         * Note that the entire tree does not need to be
         * searched. */
        AvlTreeNode minValueNode(AvlTreeNode node)
        {
            var current = node;

            /* loop down to find the leftmost leaf */
            while (current.Left != null)
            {
                current = current.Left;
            }

            return(current);
        }
        // A utility function to left
        // rotate subtree rooted with node
        // See the diagram given above.
        private static AvlTreeNode LeftRotate(AvlTreeNode node)
        {
            var originalRight     = node.Right;
            var originalRightLeft = originalRight.Left;

            // Perform rotation
            originalRight.Left = node;
            node.Right         = originalRightLeft;

            // Update heights
            IncreaseHeight(node);
            IncreaseHeight(originalRight);

            // Return new root
            return(originalRight);
        }
 private static int GetBalance(AvlTreeNode node) =>
 node == null ? 0 : GetHeight(node.Left) - GetHeight(node.Right);
 private static int GetHeight(AvlTreeNode node) => node?.Height ?? 0;
        public AvlTreeNode DeleteNode(AvlTreeNode root, int key)
        {
            // STEP 1: PERFORM STANDARD BST DELETE
            if (root == null)
            {
                return(root);
            }

            // If the key to be deleted is smaller than
            // the root's key, then it lies in left subtree
            if (key < root.Value)
            {
                root.Left = DeleteNode(root.Left, key);
            }

            // If the key to be deleted is greater than the
            // root's key, then it lies in right subtree
            else if (key > root.Value)
            {
                root.Right = DeleteNode(root.Right, key);
            }

            // if key is same as root's key, then this is the node
            // to be deleted
            else
            {
                // node with only one child or no child
                if (root.Left == null || root.Right == null)
                {
                    AvlTreeNode temp = null;
                    if (temp == root.Left)
                    {
                        temp = root.Right;
                    }
                    else
                    {
                        temp = root.Left;
                    }

                    // No child case
                    if (temp == null)
                    {
                        temp = root;
                        root = null;
                    }
                    else // One child case
                    {
                        root = temp; // Copy the contents of
                    }
                    // the non-empty child
                }
                else
                {
                    // node with two children: Get the inorder
                    // successor (smallest in the right subtree)
                    var temp = minValueNode(root.Right);

                    // Copy the inorder successor's data to this node
                    root.Value = temp.Value;

                    // Delete the inorder successor
                    root.Right = DeleteNode(root.Right, temp.Value);
                }
            }

            // If the tree had only one node then return
            if (root == null)
            {
                return(root);
            }

            // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
            root.Height = Math.Max(GetHeight(root.Left), GetHeight(root.Right)) + 1;

            // STEP 3: GET THE BALANCE FACTOR
            // OF THIS NODE (to check whether
            // this node became unbalanced)
            int balance = GetBalance(root);

            // If this node becomes unbalanced,
            // then there are 4 cases
            // Left Left Case
            if (balance > 1 && GetBalance(root.Left) >= 0)
            {
                return(RightRotate(root));
            }

            // Left Right Case
            if (balance > 1 && GetBalance(root.Left) < 0)
            {
                root.Left = LeftRotate(root.Left);
                return(RightRotate(root));
            }

            // Right Right Case
            if (balance < -1 && GetBalance(root.Right) <= 0)
            {
                return(LeftRotate(root));
            }

            // Right Left Case
            if (balance < -1 && GetBalance(root.Right) > 0)
            {
                root.Right = RightRotate(root.Right);
                return(LeftRotate(root));
            }

            return(root);
        }
 private static void IncreaseHeight(AvlTreeNode node)
 {
     node.Height = Math.Max(GetHeight(node.Left), GetHeight(node.Right)) + 1;
 }