예제 #1
0
        /// <summary>
        /// Finds the node whose key is immediately less than <paramref name="node"/>.
        /// </summary>
        /// <param name="node">Node to find the predecessor of</param>
        /// <returns>Predecessor of <paramref name="node"/></returns>
        private static IntervalTreeNode <K, V> PredecessorOf(IntervalTreeNode <K, V> node)
        {
            if (node.Left != null)
            {
                return(Maximum(node.Left));
            }
            IntervalTreeNode <K, V> parent = node.Parent;

            while (parent != null && node == parent.Left)
            {
                node   = parent;
                parent = parent.Parent;
            }
            return(parent);
        }
예제 #2
0
        /// <summary>
        /// Removes the value from the dictionary after searching for it with <paramref name="key">.
        /// </summary>
        /// <param name="key">Tree node to be removed</param>
        private void Delete(IntervalTreeNode <K, V> nodeToDelete)
        {
            IntervalTreeNode <K, V> replacementNode;

            if (LeftOf(nodeToDelete) == null || RightOf(nodeToDelete) == null)
            {
                replacementNode = nodeToDelete;
            }
            else
            {
                replacementNode = PredecessorOf(nodeToDelete);
            }

            IntervalTreeNode <K, V> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);

            if (tmp != null)
            {
                tmp.Parent = ParentOf(replacementNode);
            }

            if (ParentOf(replacementNode) == null)
            {
                _root = tmp;
            }
            else if (replacementNode == LeftOf(ParentOf(replacementNode)))
            {
                ParentOf(replacementNode).Left = tmp;
            }
            else
            {
                ParentOf(replacementNode).Right = tmp;
            }

            if (replacementNode != nodeToDelete)
            {
                nodeToDelete.Start = replacementNode.Start;
                nodeToDelete.Value = replacementNode.Value;
                nodeToDelete.End   = replacementNode.End;
                nodeToDelete.Max   = replacementNode.Max;
            }

            PropagateFull(replacementNode);

            if (tmp != null && ColorOf(replacementNode) == Black)
            {
                RestoreBalanceAfterRemoval(tmp);
            }
        }
예제 #3
0
        /// <summary>
        /// Propagate an increase in max value starting at the given node, heading up the tree.
        /// This should only be called if the max increases - not for rebalancing or removals.
        /// </summary>
        /// <param name="node">The node to start propagating from</param>
        private void PropagateIncrease(IntervalTreeNode <K, V> node)
        {
            K max = node.Max;
            IntervalTreeNode <K, V> ptr = node;

            while ((ptr = ptr.Parent) != null)
            {
                if (max.CompareTo(ptr.Max) > 0)
                {
                    ptr.Max = max;
                }
                else
                {
                    break;
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Propagate recalculating max value starting at the given node, heading up the tree.
        /// This fully recalculates the max value from all children when there is potential for it to decrease.
        /// </summary>
        /// <param name="node">The node to start propagating from</param>
        private void PropagateFull(IntervalTreeNode <K, V> node)
        {
            IntervalTreeNode <K, V> ptr = node;

            do
            {
                K max = ptr.End;

                if (ptr.Left != null && ptr.Left.Max.CompareTo(max) > 0)
                {
                    max = ptr.Left.Max;
                }

                if (ptr.Right != null && ptr.Right.Max.CompareTo(max) > 0)
                {
                    max = ptr.Right.Max;
                }

                ptr.Max = max;
            } while ((ptr = ptr.Parent) != null);
        }
예제 #5
0
 public void Clear()
 {
     _root  = null;
     _count = 0;
 }
예제 #6
0
 /// <summary>
 /// Returns the parent node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
 /// </summary>
 /// <param name="node">Node to retrieve the parent from</param>
 /// <returns>Parent of <paramref name="node"/></returns>
 private static IntervalTreeNode <K, V> ParentOf(IntervalTreeNode <K, V> node)
 {
     return(node?.Parent);
 }
예제 #7
0
 /// <summary>
 /// This method returns the right node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
 /// </summary>
 /// <param name="node">Node to retrieve the right child from</param>
 /// <returns>Right child of <paramref name="node"/></returns>
 private static IntervalTreeNode <K, V> RightOf(IntervalTreeNode <K, V> node)
 {
     return(node?.Right);
 }
예제 #8
0
 /// <summary>
 /// This method returns the left node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
 /// </summary>
 /// <param name="node">Node to retrieve the left child from</param>
 /// <returns>Left child of <paramref name="node"/></returns>
 private static IntervalTreeNode <K, V> LeftOf(IntervalTreeNode <K, V> node)
 {
     return(node?.Left);
 }
예제 #9
0
        // These methods save memory by allowing us to forego sentinel nil nodes, as well as serve as protection against NullReferenceExceptions.

        /// <summary>
        /// Returns the color of <paramref name="node"/>, or Black if it is null.
        /// </summary>
        /// <param name="node">Node</param>
        /// <returns>The boolean color of <paramref name="node"/>, or black if null</returns>
        private static bool ColorOf(IntervalTreeNode <K, V> node)
        {
            return(node == null || node.Color);
        }
예제 #10
0
        private void RestoreBalanceAfterRemoval(IntervalTreeNode <K, V> balanceNode)
        {
            IntervalTreeNode <K, V> ptr = balanceNode;

            while (ptr != _root && ColorOf(ptr) == Black)
            {
                if (ptr == LeftOf(ParentOf(ptr)))
                {
                    IntervalTreeNode <K, V> sibling = RightOf(ParentOf(ptr));

                    if (ColorOf(sibling) == Red)
                    {
                        SetColor(sibling, Black);
                        SetColor(ParentOf(ptr), Red);
                        RotateLeft(ParentOf(ptr));
                        sibling = RightOf(ParentOf(ptr));
                    }
                    if (ColorOf(LeftOf(sibling)) == Black && ColorOf(RightOf(sibling)) == Black)
                    {
                        SetColor(sibling, Red);
                        ptr = ParentOf(ptr);
                    }
                    else
                    {
                        if (ColorOf(RightOf(sibling)) == Black)
                        {
                            SetColor(LeftOf(sibling), Black);
                            SetColor(sibling, Red);
                            RotateRight(sibling);
                            sibling = RightOf(ParentOf(ptr));
                        }
                        SetColor(sibling, ColorOf(ParentOf(ptr)));
                        SetColor(ParentOf(ptr), Black);
                        SetColor(RightOf(sibling), Black);
                        RotateLeft(ParentOf(ptr));
                        ptr = _root;
                    }
                }
                else
                {
                    IntervalTreeNode <K, V> sibling = LeftOf(ParentOf(ptr));

                    if (ColorOf(sibling) == Red)
                    {
                        SetColor(sibling, Black);
                        SetColor(ParentOf(ptr), Red);
                        RotateRight(ParentOf(ptr));
                        sibling = LeftOf(ParentOf(ptr));
                    }
                    if (ColorOf(RightOf(sibling)) == Black && ColorOf(LeftOf(sibling)) == Black)
                    {
                        SetColor(sibling, Red);
                        ptr = ParentOf(ptr);
                    }
                    else
                    {
                        if (ColorOf(LeftOf(sibling)) == Black)
                        {
                            SetColor(RightOf(sibling), Black);
                            SetColor(sibling, Red);
                            RotateLeft(sibling);
                            sibling = LeftOf(ParentOf(ptr));
                        }
                        SetColor(sibling, ColorOf(ParentOf(ptr)));
                        SetColor(ParentOf(ptr), Black);
                        SetColor(LeftOf(sibling), Black);
                        RotateRight(ParentOf(ptr));
                        ptr = _root;
                    }
                }
            }
            SetColor(ptr, Black);
        }
예제 #11
0
        /// <summary>
        /// Insertion Mechanism for the interval tree. Similar to a BST insert, with the start of the range as the key.
        /// Iterates the tree starting from the root and inserts a new node where all children in the left subtree are less than <paramref name="start"/>, and all children in the right subtree are greater than <paramref name="start"/>.
        /// Each node can contain multiple values, and has an end address which is the maximum of all those values.
        /// Post insertion, the "max" value of the node and all parents are updated.
        /// </summary>
        /// <param name="start">Start of the range to insert</param>
        /// <param name="end">End of the range to insert</param>
        /// <param name="value">Value to insert</param>
        /// <param name="updateFactoryCallback">Optional factory used to create a new value if <paramref name="start"/> is already on the tree</param>
        /// <param name="outNode">Node that was inserted or modified</param>
        /// <returns>True if <paramref name="start"/> was not yet on the tree, false otherwise</returns>
        private bool BSTInsert(K start, K end, V value, Func <K, V, V> updateFactoryCallback, out IntervalTreeNode <K, V> outNode)
        {
            IntervalTreeNode <K, V> parent = null;
            IntervalTreeNode <K, V> node   = _root;

            while (node != null)
            {
                parent = node;
                int cmp = start.CompareTo(node.Start);
                if (cmp < 0)
                {
                    node = node.Left;
                }
                else if (cmp > 0)
                {
                    node = node.Right;
                }
                else
                {
                    outNode = node;

                    if (updateFactoryCallback != null)
                    {
                        // Replace
                        node.Value = updateFactoryCallback(start, node.Value);

                        int endCmp = end.CompareTo(node.End);

                        if (endCmp > 0)
                        {
                            node.End = end;
                            if (end.CompareTo(node.Max) > 0)
                            {
                                node.Max = end;
                                PropagateIncrease(node);
                                RestoreBalanceAfterInsertion(node);
                            }
                        }
                        else if (endCmp < 0)
                        {
                            node.End = end;
                            PropagateFull(node);
                        }
                    }

                    return(false);
                }
            }
            IntervalTreeNode <K, V> newNode = new IntervalTreeNode <K, V>(start, end, value, parent);

            if (newNode.Parent == null)
            {
                _root = newNode;
            }
            else if (start.CompareTo(parent.Start) < 0)
            {
                parent.Left = newNode;
            }
            else
            {
                parent.Right = newNode;
            }

            PropagateIncrease(newNode);
            _count++;
            RestoreBalanceAfterInsertion(newNode);
            outNode = newNode;
            return(true);
        }