Пример #1
0
        internal static RopeNode <T> Concat(RopeNode <T> left, RopeNode <T> right)
        {
            if (left.length == 0)
            {
                return(right);
            }
            if (right.length == 0)
            {
                return(left);
            }

            if (left.length + right.length <= NodeSize)
            {
                left = left.CloneIfShared();
                // left is guaranteed to be leaf node after cloning:
                // - it cannot be function node (due to clone)
                // - it cannot be concat node (too short)
                right.CopyTo(0, left.contents, left.length, right.length);
                left.length += right.length;
                return(left);
            }
            else
            {
                RopeNode <T> concatNode = new RopeNode <T>();
                concatNode.left   = left;
                concatNode.right  = right;
                concatNode.length = left.length + right.length;
                concatNode.Rebalance();
                return(concatNode);
            }
        }
Пример #2
0
        /// <summary>
        /// Balances this node and recomputes the 'height' field.
        /// This method assumes that the children of this node are already balanced and have an up-to-date 'height' value.
        /// </summary>
        internal void Rebalance()
        {
            // Rebalance() shouldn't be called on shared nodes - it's only called after modifications!
            Debug.Assert(!isShared);
            // leaf nodes are always balanced (we don't use 'height' to detect leaf nodes here
            // because Balance is supposed to recompute the height).
            if (left == null)
            {
                return;
            }

            // ensure we didn't miss a MergeIfPossible step
            Debug.Assert(this.length > NodeSize);

            // We need to loop until it's balanced. Rotations might cause two small leaves to combine to a larger one,
            // which changes the height and might mean we need additional balancing steps.
            while (Math.Abs(this.Balance) > 1)
            {
                // AVL balancing
                // note: because we don't care about the identity of concat nodes, this works a little different than usual
                // tree rotations: in our implementation, the "this" node will stay at the top, only its children are rearranged
                if (this.Balance > 1)
                {
                    if (right.Balance < 0)
                    {
                        right = right.CloneIfShared();
                        right.RotateRight();
                    }
                    this.RotateLeft();
                    // If 'this' was unbalanced by more than 2, we've shifted some of the inbalance to the left node; so rebalance that.
                    this.left.Rebalance();
                }
                else if (this.Balance < -1)
                {
                    if (left.Balance > 0)
                    {
                        left = left.CloneIfShared();
                        left.RotateLeft();
                    }
                    this.RotateRight();
                    // If 'this' was unbalanced by more than 2, we've shifted some of the inbalance to the right node; so rebalance that.
                    this.right.Rebalance();
                }
            }

            Debug.Assert(Math.Abs(this.Balance) <= 1);
            this.height = (byte)(1 + Math.Max(left.height, right.height));
        }