private void SearchSubtree(IntervalNode <TKey, TValue> node, Interval <TKey> i, List <KeyValuePair <Interval <TKey>, TValue> > result) { if (node == Sentinel) { return; } if (node.Left != Sentinel) { SearchSubtree(node.Left, i, result); } if (i.Overlaps(node.Interval)) { foreach (var v in node.Values) { result.Add(new KeyValuePair <Interval <TKey>, TValue>(node.Interval, v)); } } // Interval start is greater than largest endpoint in this subtree if (node.Right != Sentinel && i.Start.CompareTo(node.MaxEnd) <= 0) { SearchSubtree(node.Right, i, result); } }
/// <summary> /// General left rotation /// </summary> /// <param name="node">top of rotated subtree</param> private void RotateLeft(IntervalNode <TKey, TValue> node) { var pivot = node.Right; NodeDirection dir = node.ParentDirection; var parent = node.Parent; var tempTree = pivot.Left; pivot.Left = node; node.Parent = pivot; node.Right = tempTree; if (tempTree != Sentinel) { tempTree.Parent = node; } if (dir == NodeDirection.LEFT) { parent.Right = pivot; } else if (dir == NodeDirection.RIGHT) { parent.Left = pivot; } else { Root = pivot; } pivot.Parent = parent; pivot.RecalculateMaxEnd(); node.RecalculateMaxEnd(); }
public IntervalTree() { Root = Sentinel; Root.Left = Sentinel; Root.Right = Sentinel; Root.Parent = Sentinel; }
private IntervalNode <TKey, TValue> FindInterval(IntervalNode <TKey, TValue> tree, Interval <TKey> i) { while (tree != Sentinel) { if (tree.Interval.CompareTo(i) > 0) { tree = tree.Left; continue; } if (tree.Interval.CompareTo(i) < 0) { tree = tree.Right; continue; } if (tree.Interval.CompareTo(i) == 0) { return(tree); } } return(Sentinel); }
private void RemoveNode(IntervalNode <TKey, TValue> node) { if (node == Sentinel) { return; } IntervalNode <TKey, TValue> temp = node; if (node.Right != Sentinel && node.Left != Sentinel) { // Trick when deleting node with both children, switch it with closest in order node // swap values and delete the bottom node converting it to other cases temp = node.GetSuccessor(); node.Interval = temp.Interval; node.RecalculateMaxEnd(); while (node.Parent != Sentinel) { node = node.Parent; node.RecalculateMaxEnd(); } } node = temp; temp = node.Left != Sentinel ? node.Left : node.Right; // we will replace node with temp and delete node temp.Parent = node.Parent; if (node.IsRoot) { Root = temp; // Set new root } else { // Reattach node to parent if (node.ParentDirection == NodeDirection.RIGHT) { node.Parent.Left = temp; } else { node.Parent.Right = temp; } IntervalNode <TKey, TValue> maxAux = node.Parent; maxAux.RecalculateMaxEnd(); while (maxAux.Parent != Sentinel) { maxAux = maxAux.Parent; maxAux.RecalculateMaxEnd(); } } if (node.Color == NodeColor.BLACK) { RenewConstraintsAfterDelete(temp); } }
/// <summary> /// Validates and applies RB-tree constaints to node /// </summary> /// <param name="node">node to be validated and fixed</param> private void RenewConstraintsAfterInsert(IntervalNode <TKey, TValue> node) { if (node.Parent == Sentinel) { return; } if (node.Parent.Color == NodeColor.BLACK) { return; } var uncle = node.Uncle; if (uncle != Sentinel && uncle.Color == NodeColor.RED) { node.Parent.Color = uncle.Color = NodeColor.BLACK; var gparent = node.GrandParent; if (gparent != Sentinel && !gparent.IsRoot) { gparent.Color = NodeColor.RED; RenewConstraintsAfterInsert(gparent); } } else { if (node.ParentDirection == NodeDirection.LEFT && node.Parent.ParentDirection == NodeDirection.RIGHT) { RotateLeft(node.Parent); node = node.Left; } else if (node.ParentDirection == NodeDirection.RIGHT && node.Parent.ParentDirection == NodeDirection.LEFT) { RotateRight(node.Parent); node = node.Right; } node.Parent.Color = NodeColor.BLACK; if (node.GrandParent == Sentinel) { return; } node.GrandParent.Color = NodeColor.RED; if (node.ParentDirection == NodeDirection.RIGHT) { RotateRight(node.GrandParent); } else { RotateLeft(node.GrandParent); } } }
/// <summary> /// Insert new interval to interval tree /// </summary> /// <param name="interval">interval to add</param> public void Add(Interval <TKey> interval, TValue value) { if (Root == Sentinel) { var node = new IntervalNode <TKey, TValue>(interval, value); node.Color = NodeColor.BLACK; Root = node; } else { InsertInterval(interval, value, Root); } }
/// <summary> /// Recursively descends to the correct spot for interval insertion in the tree /// When a free spot is found for the node, it is attached and tree state is validated /// </summary> /// <param name="interval">interval to be added</param> /// <param name="currentNode">subtree accessed in recursion</param> private void InsertInterval(Interval <TKey> interval, TValue value, IntervalNode <TKey, TValue> currentNode) { IntervalNode <TKey, TValue> addedNode = Sentinel; if (interval.CompareTo(currentNode.Interval) < 0) { if (currentNode.Left == Sentinel) { addedNode = new IntervalNode <TKey, TValue>(interval, value); addedNode.Color = NodeColor.RED; currentNode.Left = addedNode; addedNode.Parent = currentNode; } else { InsertInterval(interval, value, currentNode.Left); return; } } else if (interval.CompareTo(currentNode.Interval) > 0) { if (currentNode.Right == Sentinel) { addedNode = new IntervalNode <TKey, TValue>(interval, value); addedNode.Color = NodeColor.RED; currentNode.Right = addedNode; addedNode.Parent = currentNode; } else { InsertInterval(interval, value, currentNode.Right); return; } } else { currentNode.Values.AddFirst(value); return; } addedNode.Parent.RecalculateMaxEnd(); RenewConstraintsAfterInsert(addedNode); Root.Color = NodeColor.BLACK; }
/// <summary> /// Recursively descends down the tree and adds valids results to the resultset /// </summary> /// <param name="node">subtree to be searched</param> /// <param name="val">value to be searched for</param> /// <param name="result">current resultset</param> private void SearchSubtree(IntervalNode <TKey, TValue> node, TKey val, List <KeyValuePair <Interval <TKey>, TValue> > result) { if (node == Sentinel) { return; } // Value is higher than any interval in this subtree if (val.CompareTo(node.MaxEnd) > 0) { return; } if (node.Left != Sentinel) { SearchSubtree(node.Left, val, result); } if (node.Interval.Contains(val)) { foreach (var v in node.Values) { result.Add(new KeyValuePair <Interval <TKey>, TValue>(node.Interval, v)); } } if (val.CompareTo(node.Interval.Start) < 0) { return; } if (node.Right != Sentinel) { SearchSubtree(node.Right, val, result); } }
private IEnumerable <KeyValuePair <Interval <TKey>, IEnumerable <TValue> > > InOrderWalk(IntervalNode <TKey, TValue> node) { if (node.Left != Sentinel) { foreach (var val in InOrderWalk(node.Left)) { yield return(val); } } if (node != Sentinel) { yield return(new KeyValuePair <Interval <TKey>, IEnumerable <TValue> >(node.Interval, node.Values)); } if (node.Right != Sentinel) { foreach (var val in InOrderWalk(node.Right)) { yield return(val); } } }
/// <summary> /// Ensures constraints still apply after node deletion /// /// - made with the help of algorithm from Cormen et Al. Introduction to Algorithms 2nd ed. /// </summary> /// <param name="node"></param> private void RenewConstraintsAfterDelete(IntervalNode <TKey, TValue> node) { // Need to bubble up and fix while (node != Root && node.Color == NodeColor.BLACK) { if (node.ParentDirection == NodeDirection.RIGHT) { IntervalNode <TKey, TValue> aux = node.Parent.Right; if (aux.Color == NodeColor.RED) { aux.Color = NodeColor.BLACK; node.Parent.Color = NodeColor.RED; RotateLeft(node.Parent); aux = node.Parent.Right; } if (aux.Left.Color == NodeColor.BLACK && aux.Right.Color == NodeColor.BLACK) { aux.Color = NodeColor.RED; node = node.Parent; } else { if (aux.Right.Color == NodeColor.BLACK) { aux.Left.Color = NodeColor.BLACK; aux.Color = NodeColor.RED; RotateRight(aux); aux = node.Parent.Right; } aux.Color = node.Parent.Color; node.Parent.Color = NodeColor.BLACK; aux.Right.Color = NodeColor.BLACK; RotateLeft(node.Parent); node = Root; } } else { IntervalNode <TKey, TValue> aux = node.Parent.Left; if (aux.Color == NodeColor.RED) { aux.Color = NodeColor.BLACK; node.Parent.Color = NodeColor.RED; RotateRight(node.Parent); aux = node.Parent.Left; } if (aux.Left.Color == NodeColor.BLACK && aux.Right.Color == NodeColor.BLACK) { aux.Color = NodeColor.RED; node = node.Parent; } else { if (aux.Left.Color == NodeColor.BLACK) { aux.Right.Color = NodeColor.BLACK; aux.Color = NodeColor.RED; RotateLeft(aux); aux = node.Parent.Left; } aux.Color = node.Parent.Color; node.Parent.Color = NodeColor.BLACK; aux.Left.Color = NodeColor.BLACK; RotateRight(node.Parent); node = Root; } } } node.Color = NodeColor.BLACK; }
public int CompareTo(IntervalNode <TKey, TValue> other) { return(Interval.CompareTo(other.Interval)); }