예제 #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>
        /// 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;
                }
            }
        }
예제 #3
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);
        }
예제 #4
0
 public void Clear()
 {
     _root  = null;
     _count = 0;
 }
예제 #5
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);
 }
예제 #6
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);
 }
예제 #7
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);
 }
예제 #8
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);
        }
예제 #9
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);
        }
예제 #10
0
        /// <summary>
        /// Removes instances of <paramref name="value"> from the dictionary after searching for it with <paramref name="key">.
        /// </summary>
        /// <param name="key">Key to search for</param>
        /// <param name="value">Value to delete</param>
        /// <returns>Number of deleted values</returns>
        private int Delete(K key, V value)
        {
            IntervalTreeNode <K, V> nodeToDelete = GetNode(key);

            if (nodeToDelete == null)
            {
                return(0);
            }

            int removed = nodeToDelete.Values.RemoveAll(node => node.Value.Equals(value));

            if (nodeToDelete.Values.Count > 0)
            {
                if (removed > 0)
                {
                    nodeToDelete.End = nodeToDelete.Values.Max(node => node.End);

                    // Recalculate max from children and new end.
                    PropagateFull(nodeToDelete);
                }

                return(removed);
            }

            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.Values = replacementNode.Values;
                nodeToDelete.End    = replacementNode.End;
                nodeToDelete.Max    = replacementNode.Max;
            }

            PropagateFull(replacementNode);

            if (tmp != null && ColorOf(replacementNode) == Black)
            {
                RestoreBalanceAfterRemoval(tmp);
            }

            return(removed);
        }
예제 #11
0
        /// <summary>
        /// Inserts a new node into the tree with a given <paramref name="start"/>, <paramref name="end"/> and <paramref name="value"/>.
        /// </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>
        private void Insert(K start, K end, V value)
        {
            IntervalTreeNode <K, V> newNode = BSTInsert(start, end, value);

            RestoreBalanceAfterInsertion(newNode);
        }