/// <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); }
/// <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); } }
/// <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; } } }
/// <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); }
public void Clear() { _root = null; _count = 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); }
/// <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); }
/// <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); }
// 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); }
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); }
/// <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); }