Ejemplo n.º 1
0
        /// <summary>
        /// Count all the items in a custom range, under and including node.
        /// </summary>
        /// <param name="rangeTester">The delegate that defines the range.</param>
        /// <param name="node">Node to begin enumeration. May be null.</param>
        /// <param name="belowRangeTop">This node and all under it are either in the range or below it.</param>
        /// <param name="aboveRangeBottom">This node and all under it are either in the range or above it.</param>
        /// <returns>The number of items in the range, under and include node.</returns>
        private int CountRangeUnderNode(RangeTester rangeTester, Node node, bool belowRangeTop, bool aboveRangeBottom)
        {
            if (node != null) {
                if (belowRangeTop && aboveRangeBottom) {
                    // This node and all below it must be in the range. Use the predefined count.
                    return node.Count;
                }

                int compare = rangeTester(node.item);
                int count;

                if (compare == 0) {
                    count = 1;  // the node itself
                    count += CountRangeUnderNode(rangeTester, node.left, true, aboveRangeBottom);
                    count += CountRangeUnderNode(rangeTester, node.right, belowRangeTop, true);
                }
                else if (compare < 0) {
                    count = CountRangeUnderNode(rangeTester, node.right, belowRangeTop, aboveRangeBottom);
                }
                else { // compare > 0
                    count = CountRangeUnderNode(rangeTester, node.left, belowRangeTop, aboveRangeBottom);
                }

                return count;
            }
            else {
                return 0;
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Enumerate all the items in a custom range, under and including node, in reversed order.
        /// </summary>
        /// <param name="rangeTester">Tests an item against the custom range.</param>
        /// <param name="node">Node to begin enumeration. May be null.</param>
        /// <returns>An enumerable of the items, in reversed oreder.</returns>
        /// <exception cref="InvalidOperationException">The tree has an item added or deleted during the enumeration.</exception>
        private IEnumerable<T> EnumerateRangeInReversedOrder(RangeTester rangeTester, Node node)
        {
            int startStamp = changeStamp;

            if (node != null) {
                int compare = rangeTester(node.item);

                if (compare <= 0) {
                    // At least part of the range lies to the right.
                    foreach (T item in EnumerateRangeInReversedOrder(rangeTester, node.right)) {
                        yield return item;
                        CheckEnumerationStamp(startStamp);
                    }
                }

                if (compare == 0) {
                    // The item is within the range.
                    yield return node.item;
                    CheckEnumerationStamp(startStamp);
                }

                if (compare >= 0) {
                    // At least part of the range may lie to the left.
                    foreach (T item in EnumerateRangeInReversedOrder(rangeTester, node.left)) {
                        yield return item;
                        CheckEnumerationStamp(startStamp);
                    }
                }
            }
        }
Ejemplo n.º 3
0
        public void Should_create_empty_range()
        {
            var target = new RangeTester<int>();

            Assert.That(target.Lower, Is.EqualTo(default(int)));
            Assert.That(target.Upper, Is.EqualTo(default(int)));
        }
Ejemplo n.º 4
0
        public void Should_be_able_to_set_upper_case_to_inclusive()
        {
            var target = new RangeTester<int>(0, 1);

            target.IsUpperInclusive = true;

            Assert.That(target.IsUpperInclusive, Is.True);
        }
Ejemplo n.º 5
0
        public void Should_create_range_of_specified_type()
        {
            var expectedLowerBound = 0;
            var expectedUpperBound = 1;

            var target = new RangeTester<int>(expectedLowerBound, expectedUpperBound);

            Assert.That(target, Is.Not.Null);
            Assert.That(target.Lower, Is.EqualTo(expectedLowerBound));
            Assert.That(target.Upper, Is.EqualTo(expectedUpperBound));
            Assert.That(target.IsLowerInclusive, Is.True);
            Assert.That(target.IsUpperInclusive, Is.True);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Find the last item in a custom range in the tree, and it's index. The range is determined
        /// by a RangeTester delegate.
        /// </summary>
        /// <param name="rangeTester">The delegate that defines the range.</param>
        /// <param name="item">Returns the item found, if true was returned.</param>
        /// <returns>Index of the item if range is non-empty, -1 otherwise.</returns>
        public int LastItemInRange(RangeTester rangeTester, out T item)
        {
            Node node = root, found = null;
            int  curCount = 0, foundIndex = -1;

            while (node != null)
            {
                int compare = rangeTester(node.item);

                if (compare == 0)
                {
                    found = node;
                    if (node.left != null)
                    {
                        foundIndex = curCount + node.left.Count;
                    }
                    else
                    {
                        foundIndex = curCount;
                    }
                }

                if (compare <= 0)
                {
                    if (node.left != null)
                    {
                        curCount += node.left.Count + 1;
                    }
                    else
                    {
                        curCount += 1;
                    }
                    node = node.right;
                }
                else
                {
                    node = node.left;
                }
            }

            if (found != null)
            {
                item = found.item;
                return(foundIndex);
            }
            else
            {
                item = default(T);
                return(foundIndex);
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Delete all the items in a range, identified by a RangeTester delegate.
        /// </summary>
        /// <param name="rangeTester">The delegate that defines the range to delete.</param>
        /// <returns>The number of items deleted.</returns>
        public int DeleteRange(RangeTester rangeTester)
        {
            bool deleted;
            int count = 0;
            T dummy;

            do {
                deleted = DeleteItemFromRange(rangeTester, true, out dummy);
                if (deleted)
                    ++count;
            } while (deleted);

            return count;
        }
Ejemplo n.º 8
0
        public IEnumerable<S> EnumerateRange (RangeTester rangeTester)
	{
		yield break;
	}
Ejemplo n.º 9
0
        /// <summary>
        /// Deletes either the first or last item from a range, as identified by a RangeTester
        /// delegate. If the range is empty, returns false.
        /// </summary>
        /// <remarks>Top-down algorithm from Weiss. Basic plan is to move down in the tree, 
        /// rotating and recoloring along the way to always keep the current node red, which 
        /// ensures that the node we delete is red. The details are quite complex, however! </remarks>
        /// <param name="rangeTester">Range to delete from.</param>
        /// <param name="deleteFirst">If true, delete the first item from the range, else the last.</param>
        /// <param name="item">Returns the item that was deleted, if true returned.</param>
        /// <returns>True if an element was deleted, false if the range is empty.</returns>
        public bool DeleteItemFromRange(RangeTester rangeTester, bool deleteFirst, out T item)
        {
            Node node;			// The current node.
            Node parent;		// Parent of the current node.
            Node gparent;		// Grandparent of the current node.
            Node sib;			// Sibling of the current node.
            Node keyNode;		// Node with the key that is being removed.

            // The tree may be changed.
            StopEnumerations();

            if (root == null) {
                // Nothing in the tree. Go home now.
                item = default(T);
                return false;
            }

            // We decrement counts on the way down the tree. If we end up not finding an item to delete
            // we need a stack to adjust the counts back. 
            Node[] nodeStack = GetNodeStack();
            int nodeStackPtr = 0;  // first free item on the stack.

            // Start at the root.
            node = root;
            sib = parent = gparent = null;
            keyNode = null;

            // Proceed down the tree, making the current node red so it can be removed.
            for (; ; ) {
                Debug.Assert(parent == null || parent.IsRed);
                Debug.Assert(sib == null || !sib.IsRed);
                Debug.Assert(!node.IsRed);

                if ((node.left == null || !node.left.IsRed) && (node.right == null || !node.right.IsRed)) {
                    // node has two black children (null children are considered black).
                    if (parent == null) {
                        // Special case for the root.
                        Debug.Assert(node == root);
                        node.IsRed = true;
                    }
                    else if ((sib.left == null || !sib.left.IsRed) && (sib.right == null || !sib.right.IsRed)) {
                        // sib has two black children.
                        node.IsRed = true;
                        sib.IsRed = true;
                        parent.IsRed = false;
                    }
                    else {
                        if (parent.left == node && (sib.right == null || !sib.right.IsRed)) {
                            // sib has a black child on the opposite side as node.
                            Node tleft = sib.left;
                            Rotate(parent, sib, tleft);
                            sib = tleft;
                        }
                        else if (parent.right == node && (sib.left == null || !sib.left.IsRed)) {
                            // sib has a black child on the opposite side as node.
                            Node tright = sib.right;
                            Rotate(parent, sib, tright);
                            sib = tright;
                        }

                        // sib has a red child.
                        Rotate(gparent, parent, sib);
                        node.IsRed = true;
                        sib.IsRed = true;
                        sib.left.IsRed = false;
                        sib.right.IsRed = false;

                        sib.DecrementCount();
                        nodeStack[nodeStackPtr - 1] = sib;
                        parent.DecrementCount();
                        nodeStack[nodeStackPtr++] = parent;
                    }
                }

                // Compare the key and move down the tree to the correct child.
                do {
                    Node nextNode, nextSib;		// Node we've moving to, and it's sibling.

                    node.DecrementCount();
                    nodeStack[nodeStackPtr++] = node;

                    // Determine which way to move in the tree by comparing the 
                    // current item to what we're looking for.
                    int compare = rangeTester(node.item);

                    if (compare == 0) {
                        // We've found the node to remove. Remember it, then keep traversing the
                        // tree to either find the first/last of equal keys, and if needed, the predecessor
                        // or successor (the actual node to be removed).
                        keyNode = node;
                        if (deleteFirst) {
                            nextNode = node.left; nextSib = node.right;
                        }
                        else {
                            nextNode = node.right; nextSib = node.left;
                        }
                    }
                    else if (compare > 0) {
                        nextNode = node.left; nextSib = node.right;
                    }
                    else {
                        nextNode = node.right; nextSib = node.left;
                    }

                    // Have we reached the end of our tree walk?
                    if (nextNode == null)
                        goto FINISHED;

                    // Move down the tree.
                    gparent = parent;
                    parent = node;
                    node = nextNode;
                    sib = nextSib;
                } while (!parent.IsRed && node.IsRed);

                if (!parent.IsRed) {
                    Debug.Assert(!node.IsRed);
                    // moved to a black child.
                    Rotate(gparent, parent, sib);

                    sib.DecrementCount();
                    nodeStack[nodeStackPtr - 1] = sib;
                    parent.DecrementCount();
                    nodeStack[nodeStackPtr++] = parent;

                    sib.IsRed = false;
                    parent.IsRed = true;
                    gparent = sib;
                    sib = (parent.left == node) ? parent.right : parent.left;
                }
            }

        FINISHED:
            if (keyNode == null) {
                // We never found a node to delete.

                // Return counts back to their previous value.
                for (int i = 0; i < nodeStackPtr; ++i)
                    nodeStack[i].IncrementCount();

                // Color the root black, in case it was colored red above.
                if (root != null)
                    root.IsRed = false;

                item = default(T);
                return false;
            }

            // Return the item from the node we're deleting.
            item = keyNode.item;

            // At a leaf or a node with one child which is a leaf. Remove the node.
            if (keyNode != node) {
                // The node we want to delete is interior. Move the item from the
                // node we're actually deleting to the key node.
                keyNode.item = node.item;
            }

            // If we have one child, replace the current with the child, otherwise,
            // replace the current node with null.
            Node replacement;
            if (node.left != null) {
                replacement = node.left;
                Debug.Assert(!node.IsRed && replacement.IsRed);
                replacement.IsRed = false;
            }
            else if (node.right != null) {
                replacement = node.right;
                Debug.Assert(!node.IsRed && replacement.IsRed);
                replacement.IsRed = false;
            }
            else
                replacement = null;

            if (parent == null) {
                Debug.Assert(root == node);
                root = replacement;
            }
            else if (parent.left == node)
                parent.left = replacement;
            else {
                Debug.Assert(parent.right == node);
                parent.right = replacement;
            }

            // Color the root black, in case it was colored red above.
            if (root != null)
                root.IsRed = false;

            // Update item count.
            count -= 1;

            // And we're done.
            return true;
        }
Ejemplo n.º 10
0
 /// <summary>
 /// Enumerate the items in a custom range in the tree, in reversed order. The range is determined by 
 /// a RangeTest delegate.
 /// </summary>
 /// <param name="rangeTester">Tests an item against the custom range.</param>
 /// <returns>An IEnumerable&lt;T&gt; that enumerates the custom range in reversed order.</returns>
 /// <exception cref="InvalidOperationException">The tree has an item added or deleted during the enumeration.</exception>
 public IEnumerable<T> EnumerateRangeReversed(RangeTester rangeTester)
 {
     return EnumerateRangeInReversedOrder(rangeTester, root);
 }
Ejemplo n.º 11
0
 /// <summary>
 /// Enumerate the items in a custom range in the tree. The range is determined by 
 /// a RangeTest delegate.
 /// </summary>
 /// <param name="rangeTester">Tests an item against the custom range.</param>
 /// <returns>An IEnumerable&lt;T&gt; that enumerates the custom range in order.</returns>
 /// <exception cref="InvalidOperationException">The tree has an item added or deleted during the enumeration.</exception>
 public IEnumerable<T> EnumerateRange(RangeTester rangeTester)
 {
     return EnumerateRangeInOrder(rangeTester, root);
 }
Ejemplo n.º 12
0
 /// <summary>
 /// Count the items in a custom range in the tree. The range is determined by 
 /// a RangeTester delegate.
 /// </summary>
 /// <param name="rangeTester">The delegate that defines the range.</param>
 /// <returns>The number of items in the range.</returns>
 public int CountRange(RangeTester rangeTester)
 {
     return CountRangeUnderNode(rangeTester, root, false, false);
 }
Ejemplo n.º 13
0
 public void EnumerateRange(RangeTester rangeTester)
 {
 }