private AvlTreeNode <TKey, TValue> RotateRight(AvlTreeNode <TKey, TValue> node)
        {
            var left      = node.LeftChild;
            var leftRight = left.RightChild;
            var parent    = node.Parent;

            left.Parent     = parent;
            left.RightChild = node;
            node.LeftChild  = leftRight;
            node.Parent     = left;

            if (leftRight != null)
            {
                leftRight.Parent = node;
            }
            if (node == Root)
            {
                Root = left;
            }
            else if (parent.LeftChild == node)
            {
                parent.LeftChild = left;
            }
            else
            {
                parent.RightChild = left;
            }

            left.BalanceFactor--;
            node.BalanceFactor = -left.BalanceFactor;

            return(left);
        }
        private AvlTreeNode <TKey, TValue> RotateLeft(AvlTreeNode <TKey, TValue> node)
        {
            var right     = node.RightChild;
            var rightLeft = right.LeftChild;
            var parent    = node.Parent;

            right.Parent    = parent;
            right.LeftChild = node;
            node.RightChild = rightLeft;
            node.Parent     = right;

            if (rightLeft != null)
            {
                rightLeft.Parent = node;
            }
            if (node == Root)
            {
                Root = right;
            }
            else if (parent.RightChild == node)
            {
                parent.RightChild = right;
            }
            else
            {
                parent.LeftChild = right;
            }

            right.BalanceFactor++;
            node.BalanceFactor = -right.BalanceFactor;
            return(right);
        }
        private AvlTreeNode <TKey, TValue> RotateRightLeft(AvlTreeNode <TKey, TValue> node)
        {
            var right          = node.RightChild;
            var rightLeft      = right.LeftChild;
            var parent         = node.Parent;
            var rightLeftLeft  = rightLeft.LeftChild;
            var rightLeftRight = rightLeft.RightChild;

            rightLeft.Parent     = parent;
            node.RightChild      = rightLeftLeft;
            right.LeftChild      = rightLeftRight;
            rightLeft.RightChild = right;
            rightLeft.LeftChild  = node;
            right.Parent         = rightLeft;
            node.Parent          = rightLeft;

            if (rightLeftLeft != null)
            {
                rightLeftLeft.Parent = node;
            }

            if (rightLeftRight != null)
            {
                rightLeftRight.Parent = right;
            }

            if (node == Root)
            {
                Root = rightLeft;
            }
            else if (parent.RightChild == node)
            {
                parent.RightChild = rightLeft;
            }
            else
            {
                parent.LeftChild = rightLeft;
            }

            switch (rightLeft.BalanceFactor)
            {
            case 1:
                node.BalanceFactor  = 0;
                right.BalanceFactor = -1;
                break;

            case 0:
                node.BalanceFactor  = 0;
                right.BalanceFactor = 0;
                break;

            default:
                node.BalanceFactor  = 1;
                right.BalanceFactor = 0;
                break;
            }
            rightLeft.BalanceFactor = 0;
            return(rightLeft);
        }
        private AvlTreeNode <TKey, TValue> RotateLeftRight(AvlTreeNode <TKey, TValue> node)
        {
            var left           = node.LeftChild;
            var leftRight      = left.RightChild;
            var parent         = node.Parent;
            var leftRightRight = leftRight.RightChild;
            var leftRightLeft  = leftRight.LeftChild;

            leftRight.Parent     = parent;
            node.LeftChild       = leftRightRight;
            left.RightChild      = leftRightLeft;
            leftRight.LeftChild  = left;
            leftRight.RightChild = node;
            left.Parent          = leftRight;
            node.Parent          = leftRight;

            if (leftRightRight != null)
            {
                leftRightRight.Parent = node;
            }

            if (leftRightLeft != null)
            {
                leftRightLeft.Parent = left;
            }

            if (node == Root)
            {
                Root = leftRight;
            }
            else if (parent.LeftChild == node)
            {
                parent.LeftChild = leftRight;
            }
            else
            {
                parent.RightChild = leftRight;
            }

            switch (leftRight.BalanceFactor)
            {
            case -1:
                node.BalanceFactor = 0;
                left.BalanceFactor = 1;
                break;

            case 0:
                node.BalanceFactor = 0;
                left.BalanceFactor = 0;
                break;

            default:
                node.BalanceFactor = -1;
                left.BalanceFactor = 0;
                break;
            }
            leftRight.BalanceFactor = 0;
            return(leftRight);
        }
        private void DeleteBalance(AvlTreeNode <TKey, TValue> node, int balance)
        {
            while (node != null)
            {
                balance = (node.BalanceFactor += balance);

                if (balance == 2)
                {
                    if (node.LeftChild.BalanceFactor >= 0)
                    {
                        node = RotateRight(node);

                        if (node.BalanceFactor == -1)
                        {
                            return;
                        }
                    }
                    else
                    {
                        node = RotateLeftRight(node);
                    }
                }
                else if (balance == -2)
                {
                    if (node.RightChild.BalanceFactor <= 0)
                    {
                        node = RotateLeft(node);

                        if (node.BalanceFactor == 1)
                        {
                            return;
                        }
                    }
                    else
                    {
                        node = RotateRightLeft(node);
                    }
                }
                else if (balance != 0)
                {
                    return;
                }

                var parent = node.Parent;

                if (parent != null)
                {
                    balance = parent.LeftChild == node ? -1 : 1;
                }

                node = parent;
            }
        }
        private static void Replace(AvlTreeNode <TKey, TValue> target, AvlTreeNode <TKey, TValue> source)
        {
            var left  = source.LeftChild;
            var right = source.RightChild;

            target.BalanceFactor = source.BalanceFactor;
            target.Item          = source.Item;
            target.LeftChild     = left;
            target.RightChild    = right;
            if (left != null)
            {
                left.Parent = target;
            }
            if (right != null)
            {
                right.Parent = target;
            }
        }
        private void InsertBalance(AvlTreeNode <TKey, TValue> node, int balance)
        {
            while (node != null)
            {
                balance = (node.BalanceFactor += balance);
                switch (balance)
                {
                case 0: return;

                case 2:
                    if (node.LeftChild.BalanceFactor == 1)
                    {
                        RotateRight(node);
                    }
                    else
                    {
                        RotateLeftRight(node);
                    }
                    return;

                case -2:
                    if (node.RightChild.BalanceFactor == -1)
                    {
                        RotateLeft(node);
                    }
                    else
                    {
                        RotateRightLeft(node);
                    }
                    return;
                }
                var parent = node.Parent;
                if (parent != null)
                {
                    balance = parent.LeftChild == node ? 1 : -1;
                }
                node = parent;
            }
        }
        public override void Add(KeyValuePair <TKey, TValue> item)
        {
            if (item.Key == null)
            {
                throw new ArgumentNullException(nameof(item.Key));
            }
            if (Root == null)
            {
                Root = new AvlTreeNode <TKey, TValue>(item);
            }
            else
            {
                var currentNode = Root;
                while (currentNode != null)
                {
                    var cmp = _comparer.Compare(currentNode.Item.Key, item.Key);
                    if (cmp == 0)
                    {
                        throw new ArgumentException($"An item with the same key has already been added. Key: {item.Key}");
                    }

                    var childIndex = cmp > 0 ? 0 : 1;
                    if (currentNode.Children[childIndex] != null)
                    {
                        currentNode = currentNode.Children[childIndex];
                    }
                    else
                    {
                        currentNode.Children[childIndex] = new AvlTreeNode <TKey, TValue>(item, parent: currentNode);
                        var balance = cmp > 0 ? 1 : -1;
                        InsertBalance(currentNode, balance);
                        break;
                    }
                }
            }
            _version++;
            _count++;
        }
        protected override void RemoveNode(AvlTreeNode <TKey, TValue> node)
        {
            var left  = node.LeftChild;
            var right = node.RightChild;

            if (left == null)
            {
                if (right == null)
                {
                    if (node == Root)
                    {
                        Root = null;
                    }
                    else
                    {
                        var parent = node.Parent;
                        if (parent.LeftChild == node)
                        {
                            parent.LeftChild = null;
                            DeleteBalance(parent, -1);
                        }
                        else
                        {
                            parent.RightChild = null;
                            DeleteBalance(parent, 1);
                        }
                    }
                }
                else
                {
                    Replace(node, right);
                    DeleteBalance(node, 0);
                }
            }
            else if (right == null)
            {
                Replace(node, left);
                DeleteBalance(node, 0);
            }
            else
            {
                var successor = right;
                if (successor.LeftChild == null)
                {
                    var parent = node.Parent;
                    successor.Parent        = parent;
                    successor.LeftChild     = left;
                    successor.BalanceFactor = node.BalanceFactor;
                    left.Parent             = successor;

                    if (node == Root)
                    {
                        Root = successor;
                    }
                    else
                    {
                        if (parent.LeftChild == node)
                        {
                            parent.LeftChild = successor;
                        }
                        else
                        {
                            parent.RightChild = successor;
                        }
                    }

                    DeleteBalance(successor, 1);
                }
                else
                {
                    while (successor.LeftChild != null)
                    {
                        successor = successor.LeftChild;
                    }

                    var parent          = node.Parent;
                    var successorParent = successor.Parent;
                    var successorRight  = successor.RightChild;

                    if (successorParent.LeftChild == successor)
                    {
                        successorParent.LeftChild = successorRight;
                    }
                    else
                    {
                        successorParent.RightChild = successorRight;
                    }

                    if (successorRight != null)
                    {
                        successorRight.Parent = successorParent;
                    }

                    successor.Parent        = parent;
                    successor.LeftChild     = left;
                    successor.BalanceFactor = node.BalanceFactor;
                    successor.RightChild    = right;
                    right.Parent            = successor;
                    left.Parent             = successor;

                    if (node == Root)
                    {
                        Root = successor;
                    }
                    else
                    {
                        if (parent.LeftChild == node)
                        {
                            parent.LeftChild = successor;
                        }
                        else
                        {
                            parent.RightChild = successor;
                        }
                    }
                    DeleteBalance(successorParent, -1);
                }
            }
            _count--;
            _version++;
        }
 public AvlTreeNode(KeyValuePair <TKey, TValue> item, int balanceFactor = 0, AvlTreeNode <TKey, TValue> left = null,
                    AvlTreeNode <TKey, TValue> right = null, AvlTreeNode <TKey, TValue> parent = null)
     : base(item, left, right, parent)
 {
     BalanceFactor = balanceFactor;
 }
 public AvlTreeNode(TKey key, TValue value, int balanceFactor = 0, AvlTreeNode <TKey, TValue> left = null, AvlTreeNode <TKey, TValue> right = null, AvlTreeNode <TKey, TValue> parent = null)
     : this(new KeyValuePair <TKey, TValue>(key, value), balanceFactor, left, right, parent)
 {
 }