/// <summary> /// Find all cells inside the given range. /// </summary> /// <returns>The range.</returns> /// <param name="start">Start.</param> /// <param name="end">End.</param> public CellTreeNode[] GetRange(double start, double end) { List <CellTreeNode> cells = new List <CellTreeNode>(); CellTreeNode cell = FindAboveOrEqualTo(start); while (cell != null && cell.Cell.Position <= end) { cells.Add(cell); cell = cell.Next(); } return(cells.ToArray()); }
public IEnumerator GetEnumerator() { CellTreeNode node = Min; if (node == null) { yield break; } while (node != null) { yield return(node.Cell); node = node.Next(); } yield break; }
public CellTree Remove(CellTreeNode node) { CellTreeNode nodeToDeleteAfterwards = null; if (node == Min) { Min = node.Next(); } else if (node == Max) { Max = node.Prev(); } if (node.Left == null && node.Right == null) { if (Root == node) { Root = null; Min = null; Max = null; return(this); } if (node.IsRed) { Replace(node, null); return(this); } // black node with no children, not root // we will delete the node afterwards. it's a 'phantom' leaf. nodeToDeleteAfterwards = node; // do we need to track the actual node, as it may be changed by a rule? } else if (node.Left != null && node.Right != null) { // we find the left-most child of right side and copy it's value to the node being deleted // The node that we copied from (left-most) can then by deleted because it // has at most 1 non-leaf child. var succesor = node.Left; while (succesor.Right != null) { succesor = succesor.Right; } // copy data from succesor node succesor.CopyTo(node); //Swap(node, succesor); return(Remove(succesor)); } if (node.Left != null || node.Right != null) { // one child is a non-leaf var child = node.Left ?? node.Right; if (!node.IsRed && child.IsRed) { // black node, red child Replace(node, child); child.IsRed = false; return(this); } if (node.IsRed && !child.IsRed) { // red node, black child Replace(node, child); return(this); } // black node with black child Replace(node, child); node = child; } while (true) { // node is now a "double black" node if (node == Root) { break; // case 1. terminal case } var sibling = node.GetSibling(); if (sibling.IsRed) { // case 2 // node is black, has black parent, and a red sibling // make sibling take the place of the parent. if (node.Parent.Left == node) { RotateLeft(node.Parent); } else { RotateRight(node.Parent); } node.Parent.IsRed = true; sibling.IsRed = false; sibling = node.GetSibling(); } else if (!node.Parent.IsRed && !sibling.IsRed && (sibling.Left == null || !sibling.Left.IsRed) && (sibling.Right == null || !sibling.Right.IsRed)) { // case 3 // node is black, black parent, black sibling with black children sibling.IsRed = true; node = node.Parent; // go to start with parent as new node. (we pushed the double black status up to the parent) continue; } else if (node.Parent.IsRed && (sibling.Left == null || !sibling.Left.IsRed) && (sibling.Right == null || !sibling.Right.IsRed)) { // case 4, terminal case node.Parent.IsRed = false; sibling.IsRed = true; break; } else if (!sibling.IsRed && node.HasSiblingWithInnerRedChild()) { // case 5 // black node, black parent, black sibling with inner red child if (node.Parent.Left == node) { RotateRight(sibling); sibling.Left.IsRed = false; } else { RotateLeft(sibling); sibling.Right.IsRed = false; } sibling.IsRed = true; sibling = node.GetSibling(); } if (!sibling.IsRed && node.HasSiblingWithOuterRedChild()) { // case 6, terminal case // black node, don't care parent's color, black sibling with outer red child and inner child with either color. if (node.Parent.Left == node) { RotateLeft(node.Parent); sibling.Right.IsRed = false; } else { RotateRight(node.Parent); sibling.Left.IsRed = false; } sibling.IsRed = node.Parent.IsRed; node.Parent.IsRed = false; // node is no longer a bouble black. break; } } if (nodeToDeleteAfterwards != null) { Replace(nodeToDeleteAfterwards, null); } Count--; return(this); }