public AvlNode <TKey, TValue> AddOrReplace([NotNull] TKey key, TValue value)
        {
            var compare = key.CompareTo(this.key);

            if (compare == 0)
            {
                this.value = value;
                return(this);
            }

            if (compare < 0)
            {
                if (this.left != null)
                {
                    this.left = this.left.AddOrReplace(key, value);

                    // Check whether rebalance is necessary and update height
                    var node = Rebalance(this);
                    node.height = CalculateHeight(node);
                    return(node);
                }
                else
                {
                    this.left   = new AvlNode <TKey, TValue>(key, value);
                    this.height = 2;
                    return(this);
                }
            }
            else
            {
                if (this.right != null)
                {
                    this.right = this.right.AddOrReplace(key, value);

                    var node = Rebalance(this);
                    node.height = CalculateHeight(node);
                    return(node);
                }
                else
                {
                    this.right  = new AvlNode <TKey, TValue>(key, value);
                    this.height = 2;
                    return(this);
                }
            }
        }
 private static AvlNode <TKey, TValue> RightLeftRotation(AvlNode <TKey, TValue> avlNode)
 {
     avlNode.right = RightRotation(avlNode.right);
     return(LeftRotation(avlNode));
 }
 private static AvlNode <TKey, TValue> LeftRightRotation(AvlNode <TKey, TValue> avlNode)
 {
     avlNode.left = LeftRotation(avlNode.left);
     return(RightRotation(avlNode));
 }
 private static int CalculateHeight(AvlNode <TKey, TValue> avlNode)
 {
     return(Math.Max(Height(avlNode.left), Height(avlNode.right)) + 1);
 }
        public bool Remove([NotNull] TKey key, out AvlNode <TKey, TValue> node)
        {
            var compare = key.CompareTo(this.key);

            if (compare == 0)
            {
                if (this.left == null)
                {
                    node = this.right;
                }
                else
                {
                    if (this.right == null)
                    {
                        node = this.left;
                    }
                    else
                    {
                        var top = MinValueNode(this.right);
                        this.right.Remove(top.key, out top);
                        top.left   = this.left;
                        top.right  = this.right;
                        top        = Rebalance(top);
                        top.height = CalculateHeight(top);
                        node       = top;
                    }
                }

                return(true);
            }

            if (compare < 0)
            {
                if (this.left != null)
                {
                    var result = this.left.Remove(key, out node);
                    if (result)
                    {
                        this.left   = node;
                        node        = Rebalance(this);
                        node.height = CalculateHeight(node);
                    }

                    return(result);
                }

                node = this;
                return(false);
            }

            if (this.right != null)
            {
                var result = this.right.Remove(key, out node);
                if (result)
                {
                    this.right  = node;
                    node        = Rebalance(this);
                    node.height = CalculateHeight(node);
                }

                return(result);
            }

            node = this;
            return(false);
        }