/// <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> /// 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> /// 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); }
/// <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); }