/// <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 <T> node, T val, List <Interval <T> > 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)) { result.Add(node.Interval); } if (val.CompareTo(node.Interval.Start) < 0) { return; } if (node.Right != Sentinel) { SearchSubtree(node.Right, val, result); } }
public IntervalTree() { this.head = new IntervalNode <T, D>(); this.intervalList = new List <Interval <T, D> >(); this.inSync = true; this.size = 0; }
public IntervalTree() { Root = Sentinel; Root.Left = Sentinel; Root.Right = Sentinel; Root.Parent = Sentinel; }
private IntervalNode <T> FindInterval(IntervalNode <T> tree, Interval <T> 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); }
/// <summary> /// General left rotation /// </summary> /// <param name="node">top of rotated subtree</param> private void RotateLeft(IntervalNode <T> 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 IntervalNode() { intervals = new OrderedDictionary <Interval <T, D>, List <Interval <T, D> > >(); center = default(D); leftNode = null; rightNode = null; }
private void RemoveNode(IntervalNode <T> node) { if (node == Sentinel) { return; } IntervalNode <T> 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 <T> maxAux = node.Parent; maxAux.RecalculateMaxEnd(); while (maxAux.Parent != Sentinel) { maxAux = maxAux.Parent; maxAux.RecalculateMaxEnd(); } } if (node.Color == NodeColor.BLACK) { RenewConstraintsAfterDelete(temp); } }
public IntervalTree(List <Interval <T, D> > intervalList) { this.head = new IntervalNode <T, D>(intervalList); this.intervalList = new List <Interval <T, D> >(); this.intervalList.AddRange(intervalList); this.inSync = true; this.size = intervalList.Count; }
/// <summary> /// Finds the min. /// </summary> /// <param name="node">The node.</param> /// <returns></returns> public static IntervalNode FindMin(IntervalNode node) { while (node != null && node.Left != null) { node = node.Left; } return(node); }
/// <summary> /// Finds the max. /// </summary> /// <param name="node">The node.</param> /// <returns></returns> public static IntervalNode FindMax(IntervalNode node) { while (node != null && node.Right != null) { node = node.Right; } return(node); }
/// <summary> /// Adds the specified arg. /// </summary> /// <param name="arg">The arg.</param> public void Add(KeyValuePair <IInterval <T>, TypeValue> arg) { bool wasAdded = false; bool wasSuccessful = false; this.Root = IntervalNode.Add(this.Root, arg, ref wasAdded, ref wasSuccessful); IntervalNode.ComputeMax(this.Root); }
public void Build() { if (!inSync) { head = new IntervalNode <T, D>(intervalList); inSync = true; size = intervalList.Count; } }
/// <summary> /// Validates and applies RB-tree constaints to node /// </summary> /// <param name="node">node to be validated and fixed</param> private void RenewConstraintsAfterInsert(IntervalNode <T> 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 <T> interval) { var node = new IntervalNode <T>(interval); if (Root == Sentinel) { node.Color = NodeColor.BLACK; Root = node; } else { InsertInterval(interval, Root); } }
public IntervalNode(List <Interval <T, D> > intervalList) { intervals = new OrderedDictionary <Interval <T, D>, List <Interval <T, D> > >(); var endpoints = new OrderedSet <D>(); foreach (var interval in intervalList) { endpoints.Add(interval.Start); endpoints.Add(interval.End); } Nullable <D> median = GetMedian(endpoints); center = median.GetValueOrDefault(); List <Interval <T, D> > left = new List <Interval <T, D> >(); List <Interval <T, D> > right = new List <Interval <T, D> >(); foreach (Interval <T, D> interval in intervalList) { if (interval.End.CompareTo(center) < 0) { left.Add(interval); } else if (interval.Start.CompareTo(center) > 0) { right.Add(interval); } else { List <Interval <T, D> > posting; if (!intervals.TryGetValue(interval, out posting)) { posting = new List <Interval <T, D> >(); intervals.Add(interval, posting); } posting.Add(interval); } } if (left.Count > 0) { leftNode = new IntervalNode <T, D>(left); } if (right.Count > 0) { rightNode = new IntervalNode <T, D>(right); } }
/// <summary> /// Deletes the interval starting at x. /// </summary> /// <param name="arg">The arg.</param> public void Delete(IInterval <T> arg) { if (Root != null) { bool wasDeleted = false; bool wasSuccessful = false; Root = IntervalNode.Delete(Root, arg, ref wasDeleted, ref wasSuccessful); if (this.Root != null) { IntervalNode.ComputeMax(this.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 <T> interval, IntervalNode <T> currentNode) { IntervalNode <T> addedNode = Sentinel; if (interval.CompareTo(currentNode.Interval) < 0) { if (currentNode.Left == Sentinel) { addedNode = new IntervalNode <T>(interval); addedNode.Color = NodeColor.RED; currentNode.Left = addedNode; addedNode.Parent = currentNode; } else { InsertInterval(interval, currentNode.Left); return; } } else if (interval.CompareTo(currentNode.Interval) > 0) { if (currentNode.Right == Sentinel) { addedNode = new IntervalNode <T>(interval); addedNode.Color = NodeColor.RED; currentNode.Right = addedNode; addedNode.Parent = currentNode; } else { InsertInterval(interval, currentNode.Right); return; } } else { return; } addedNode.Parent.RecalculateMaxEnd(); RenewConstraintsAfterInsert(addedNode); Root.Color = NodeColor.BLACK; }
private String NodeString(IntervalNode <T, D> node, int level) { if (node == null) { return(""); } var sb = new StringBuilder(); for (int i = 0; i < level; i++) { sb.Append("\t"); } sb.Append(node + "\n"); sb.Append(NodeString(node.Left, level + 1)); sb.Append(NodeString(node.Right, level + 1)); return(sb.ToString()); }
/// <summary> /// Computes the max. /// </summary> /// <param name="node">The node.</param> public static void ComputeMax(IntervalNode node) { if (node.Left == null && node.Right == null) { node.Max = node.MaxRange; } else if (node.Left == null) { node.Max = Max(node.MaxRange, node.Right.Max); } else if (node.Right == null) { node.Max = Max(node.MaxRange, node.Left.Max); } else { node.Max = Max(node.MaxRange, Max(node.Left.Max, node.Right.Max)); } }
/// <summary> /// Searches the specified subtree. /// </summary> /// <param name="subtree">The subtree.</param> /// <param name="data">The data.</param> /// <returns></returns> public static IntervalNode Search(IntervalNode subtree, IInterval <T> data) { if (subtree != null) { if (data.Start.CompareTo(subtree.Data.Key.Start) < 0) { return(Search(subtree.Left, data)); } else if (data.Start.CompareTo(subtree.Data.Key.Start) > 0) { return(Search(subtree.Right, data)); } else { return(subtree); } } else { return(null); } }
private void SearchSubtree(IntervalNode <T> node, Interval <T> i, List <Interval <T> > result) { if (node == Sentinel) { return; } if (node.Left != Sentinel) { SearchSubtree(node.Left, i, result); } if (i.Overlaps(node.Interval)) { result.Add(node.Interval); } // 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); } }
private IEnumerable <Interval <T> > InOrderWalk(IntervalNode <T> node) { if (node.Left != Sentinel) { foreach (Interval <T> val in InOrderWalk(node.Left)) { yield return(val); } } if (node != Sentinel) { yield return(node.Interval); } if (node.Right != Sentinel) { foreach (Interval <T> val in InOrderWalk(node.Right)) { yield return(val); } } }
/// <summary> /// Rotates lefts this instance. /// Assumes that this.Right != null /// </summary> /// <returns></returns> private IntervalNode RotateLeft() { var right = this.Right; Debug.Assert(this.Right != null); this.Right = right.Left; ComputeMax(this); #if TREE_WITH_PARENT_POINTERS var parent = this.Parent; if (right.Left != null) { right.Left.Parent = this; } #endif right.Left = this; ComputeMax(right); #if TREE_WITH_PARENT_POINTERS this.Parent = right; if (parent != null) { if (parent.Left == this) { parent.Left = right; } else { parent.Right = right; } } right.Parent = parent; #endif return(right); }
public int CompareTo(IntervalNode <T> other) { return(Interval.CompareTo(other.Interval)); }
/// <summary> /// Returns all intervals beginning at the specified start value /// </summary> /// <param name="subtree">The subtree.</param> /// <param name="data">The data.</param> /// <returns></returns> public static List <KeyValuePair <IInterval <T>, TypeValue> > GetIntervalsStartingAt(IntervalNode subtree, T start) { if (subtree != null) { if (start.CompareTo(subtree.Data.Key.Start) < 0) { return(GetIntervalsStartingAt(subtree.Left, start)); } else if (start.CompareTo(subtree.Data.Key.Start) > 0) { return(GetIntervalsStartingAt(subtree.Right, start)); } else { var result = new List <KeyValuePair <IInterval <T>, TypeValue> >(); result.Add(subtree.Data); if (subtree.Range != null) { foreach (var value in subtree.Range) { var kInterval = new Interval <T>(start, value.Key); result.Add(new KeyValuePair <IInterval <T>, TypeValue>(kInterval, value.Value)); } } return(result); } } else { return(null); } }
/// <summary> /// Deletes the specified node. /// </summary> /// <param name="node">The node.</param> /// <param name="arg">The arg.</param> /// <returns></returns> public static IntervalNode Delete(IntervalNode node, IInterval <T> arg, ref bool wasDeleted, ref bool wasSuccessful) { int cmp = arg.Start.CompareTo(node.Data.Key.Start); if (cmp < 0) { if (node.Left != null) { node.Left = Delete(node.Left, arg, ref wasDeleted, ref wasSuccessful); if (wasDeleted) { node.Balance++; } } } else if (cmp == 0) { int position = -1; // find the exact interval to delete based on the Y value.. consider changing this code if (arg.End.CompareTo(node.Data.Key.End) == 0) { position = 0; } else { if (node.Range != null && node.Range.Count > 0) { for (int k = 0; k < node.Range.Count; k++) { if (arg.End.CompareTo(node.Range[k].Key) == 0) { position = k + 1; } } } } // couldn't find the interval in the tree, throw an exception if (position == -1) { throw new ArgumentOutOfRangeException("arg", "cannot delete the specified interval. invalid argument."); } if (position > 0) { // we're counting the value stored in the node.Data.Value as position 0, all values stored in Range represent position + 1, position + 2, ...etc if (node.Range != null && position - 1 < node.Range.Count) { node.Range.RemoveAt(position - 1); if (node.Range.Count == 0) { node.Range = null; } wasSuccessful = true; } } else if (position == 0 && node.Range != null && node.Range.Count > 0) { node.Data = new KeyValuePair <IInterval <T>, TypeValue>( new Interval <T>(node.Data.Key.Start, node.Range[0].Key), node.Range[0].Value); node.Range.RemoveAt(0); if (node.Range.Count == 0) { node.Range = null; } wasSuccessful = true; } else { if (node.Left != null && node.Right != null) { var min = FindMin(node.Right); var data = node.Data; var range = node.Range; node.Data = min.Data; node.Range = min.Range; min.Data = data; min.Range = range; wasDeleted = false; node.Right = Delete(node.Right, data.Key, ref wasDeleted, ref wasSuccessful); if (wasDeleted) { node.Balance--; } } else if (node.Left == null) { wasDeleted = true; wasSuccessful = true; return(node.Right); } else { wasDeleted = true; wasSuccessful = true; return(node.Left); } } } else { if (node.Right != null) { node.Right = Delete(node.Right, arg, ref wasDeleted, ref wasSuccessful); if (wasDeleted) { node.Balance--; } } } ComputeMax(node); if (wasDeleted) { if (node.Balance == 1 || node.Balance == -1) { wasDeleted = false; return(node); } else if (node.Balance == -2) { if (node.Left.Balance == 1) { int leftRightBalance = node.Left.Right.Balance; node.Left = node.Left.RotateLeft(); node = node.RotateRight(); node.Balance = 0; node.Left.Balance = (leftRightBalance == 1) ? -1 : 0; node.Right.Balance = (leftRightBalance == -1) ? 1 : 0; } else if (node.Left.Balance == -1) { node = node.RotateRight(); node.Balance = 0; node.Right.Balance = 0; } else if (node.Left.Balance == 0) { node = node.RotateRight(); node.Balance = 1; node.Right.Balance = -1; wasDeleted = false; } } else if (node.Balance == 2) { if (node.Right.Balance == -1) { int rightLeftBalance = node.Right.Left.Balance; node.Right = node.Right.RotateRight(); node = node.RotateLeft(); node.Balance = 0; node.Left.Balance = (rightLeftBalance == 1) ? -1 : 0; node.Right.Balance = (rightLeftBalance == -1) ? 1 : 0; } else if (node.Right.Balance == 1) { node = node.RotateLeft(); node.Balance = 0; node.Left.Balance = 0; } else if (node.Right.Balance == 0) { node = node.RotateLeft(); node.Balance = -1; node.Left.Balance = 1; wasDeleted = false; } } } return(node); }
/// <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 <T> node) { // Need to bubble up and fix while (node != Root && node.Color == NodeColor.BLACK) { if (node.ParentDirection == NodeDirection.RIGHT) { IntervalNode <T> 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 <T> 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; }
/// <summary> /// Searches the specified arg. /// </summary> /// <param name="arg">The arg.</param> /// <returns></returns> public List <KeyValuePair <IInterval <T>, TypeValue> > GetIntervalsStartingAt(T arg) { return(IntervalNode.GetIntervalsStartingAt(Root, arg)); }
/// <summary> /// Adds the specified elem. /// </summary> /// <param name="elem">The elem.</param> /// <param name="data">The data.</param> /// <returns></returns> public static IntervalNode Add( IntervalNode elem, KeyValuePair <IInterval <T>, TypeValue> data, ref bool wasAdded, ref bool wasSuccessful) { if (elem == null) { elem = new IntervalNode { Data = data, Left = null, Right = null, Balance = 0, Max = data.Key.End }; wasAdded = true; wasSuccessful = true; } else { if (data.Key.Start.CompareTo(elem.Data.Key.Start) < 0) { elem.Left = Add(elem.Left, data, ref wasAdded, ref wasSuccessful); if (wasAdded) { elem.Balance--; if (elem.Balance == 0) { wasAdded = false; } } #if TREE_WITH_PARENT_POINTERS elem.Left.Parent = elem; #endif if (elem.Balance == -2) { if (elem.Left.Balance == 1) { int elemLeftRightBalance = elem.Left.Right.Balance; elem.Left = elem.Left.RotateLeft(); elem = elem.RotateRight(); elem.Balance = 0; elem.Left.Balance = elemLeftRightBalance == 1 ? -1 : 0; elem.Right.Balance = elemLeftRightBalance == -1 ? 1 : 0; } else if (elem.Left.Balance == -1) { elem = elem.RotateRight(); elem.Balance = 0; elem.Right.Balance = 0; } wasAdded = false; } } else if (data.Key.Start.CompareTo(elem.Data.Key.Start) > 0) { elem.Right = Add(elem.Right, data, ref wasAdded, ref wasSuccessful); if (wasAdded) { elem.Balance++; if (elem.Balance == 0) { wasAdded = false; } } #if TREE_WITH_PARENT_POINTERS elem.Right.Parent = elem; #endif if (elem.Balance == 2) { if (elem.Right.Balance == -1) { int elemRightLeftBalance = elem.Right.Left.Balance; elem.Right = elem.Right.RotateRight(); elem = elem.RotateLeft(); elem.Balance = 0; elem.Left.Balance = elemRightLeftBalance == 1 ? -1 : 0; elem.Right.Balance = elemRightLeftBalance == -1 ? 1 : 0; } else if (elem.Right.Balance == 1) { elem = elem.RotateLeft(); elem.Balance = 0; elem.Left.Balance = 0; } wasAdded = false; } } else { // we allow multiple values per key if (elem.Range == null) { elem.Range = new List <KeyValuePair <T, TypeValue> >(); } //always store the max Y value in the node.Data itself .. store the Range list in decreasing order if (data.Key.End.CompareTo(elem.Data.Key.End) > 0) { elem.Range.Insert(0, new KeyValuePair <T, TypeValue>(elem.Data.Key.End, elem.Data.Value)); elem.Data = data; } else { for (int i = 0; i < elem.Range.Count; i++) { if (data.Key.End.CompareTo(elem.Range[i].Key) >= 0) { elem.Range.Insert(i, new KeyValuePair <T, TypeValue>(data.Key.End, data.Value)); break; } } } wasSuccessful = true; } } ComputeMax(elem); return(elem); }