/// <summary> /// Moves to the next node /// </summary> /// <returns>True if the move to the next node was successful; otherwise false</returns> public bool MoveNext() { if (this.current == null) { this.current = this.avlTree.GetFirstNode(); } else { this.current = this.current.GetNextNode(); } // Should check for an empty tree too :-) if (this.current == null) { return(false); } return(true); }
/// <summary> /// Replace a node /// </summary> /// <param name="target">The node to replace</param> /// <param name="source">The replacing node</param> private static void Replace(AvlNode <T> target, AvlNode <T> source) { AvlNode <T> left = source.Left; AvlNode <T> right = source.Right; target.Balance = source.Balance; target.Item = source.Item; target.Left = left; target.Right = right; if (left != null) { left.Parent = target; } if (right != null) { right.Parent = target; } }
/// <summary> /// Find child max height /// </summary> /// <param name="node">A node in the tree</param> /// <returns>The height</returns> private int RecursiveGetChildMaxHeight(AvlNode <T> node) { if (node == null) { return(0); } int leftHeight = 0; if (node.Left != null) { leftHeight = this.RecursiveGetChildMaxHeight(node.Left); } int rightHeight = 0; if (node.Right != null) { rightHeight = this.RecursiveGetChildMaxHeight(node.Right); } return(1 + Math.Max(leftHeight, rightHeight)); }
/// <summary> /// Gets a node with the provided item /// </summary> /// <param name="item">An item to find</param> /// <returns>The node with that item</returns> protected AvlNode <T> GetNode(T item) { AvlNode <T> node = this.root; while (node != null) { int compareResult = this.comparer.Compare(item, node.Item); if (compareResult < 0) { node = node.Left; } else if (compareResult > 0) { node = node.Right; } else { return(node); } } return(null); }
/// <summary> /// Removes a node /// </summary> /// <param name="item">item to remove</param> /// <returns>True if successful; otherwise false</returns> public virtual bool Remove(T item) { AvlNode <T> node = this.root; while (node != null) { if (this.comparer.Compare(item, node.Item) < 0) { node = node.Left; } else if (this.comparer.Compare(item, node.Item) > 0) { node = node.Right; } else { this.RemoveNode(node); return(true); } } return(false); }
/// <summary> /// Gets a value indicating whether the tree contains an item /// </summary> /// <param name="item">The item to find</param> /// <returns>True if the item is found; otherwise false;</returns> public bool Contains(T item) { AvlNode <T> node = this.root; while (node != null) { int compareResult = this.comparer.Compare(item, node.Item); if (compareResult < 0) { node = node.Left; } else if (compareResult > 0) { node = node.Right; } else { return(true); } } return(false); }
/// <summary> /// Iterate over each points to see if we can add it has a ConvexHull point. /// It is specific by Quadrant to improve efficiency. /// </summary> /// <param name="point">a point</param> //// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override void ProcessPoint(ref MutablePoint point) { this.CurrentNode = this.Root; AvlNode <MutablePoint> currentPrevious = null; AvlNode <MutablePoint> currentNext = null; while (this.CurrentNode != null) { var insertionSide = Side.Unknown; if (point.X > this.CurrentNode.Item.X) { if (this.CurrentNode.Left != null) { this.CurrentNode = this.CurrentNode.Left; continue; } currentPrevious = this.CurrentNode.GetPreviousNode(); if (CanQuickReject(ref point, ref currentPrevious.Item)) { return; } if (!this.IsPointToTheRightOfOthers(currentPrevious.Item, this.CurrentNode.Item, point)) { return; } // Ensure to have no duplicate if (this.CurrentNode.Item == point) { return; } insertionSide = Side.Left; } else if (point.X < this.CurrentNode.Item.X) { if (this.CurrentNode.Right != null) { this.CurrentNode = this.CurrentNode.Right; continue; } currentNext = this.CurrentNode.GetNextNode(); if (CanQuickReject(ref point, ref currentNext.Item)) { return; } if (!this.IsPointToTheRightOfOthers(this.CurrentNode.Item, currentNext.Item, point)) { return; } // Ensure to have no duplicate if (this.CurrentNode.Item == point) { continue; } insertionSide = Side.Right; } else { if (point.Y <= this.CurrentNode.Item.Y) { return; // invalid point } // Replace CurrentNode point with point this.CurrentNode.Item = point; this.InvalidateNeighbors(this.CurrentNode.GetPreviousNode(), this.CurrentNode, this.CurrentNode.GetNextNode()); return; } // We should insert the point // Try to optimize and verify if can replace a node instead insertion to minimize tree balancing if (insertionSide == Side.Right) { currentPrevious = this.CurrentNode.GetPreviousNode(); if (currentPrevious != null && !this.IsPointToTheRightOfOthers(currentPrevious.Item, point, this.CurrentNode.Item)) { this.CurrentNode.Item = point; this.InvalidateNeighbors(currentPrevious, this.CurrentNode, currentNext); return; } var nextNext = currentNext.GetNextNode(); if (nextNext != null && !this.IsPointToTheRightOfOthers(point, nextNext.Item, currentNext.Item)) { currentNext.Item = point; this.InvalidateNeighbors(null, currentNext, nextNext); return; } } else { // Left currentNext = this.CurrentNode.GetNextNode(); if (currentNext != null && !this.IsPointToTheRightOfOthers(point, currentNext.Item, this.CurrentNode.Item)) { this.CurrentNode.Item = point; this.InvalidateNeighbors(currentPrevious, this.CurrentNode, currentNext); return; } var previousPrevious = currentPrevious.GetPreviousNode(); if (previousPrevious != null && !this.IsPointToTheRightOfOthers(previousPrevious.Item, point, currentPrevious.Item)) { currentPrevious.Item = point; this.InvalidateNeighbors(previousPrevious, currentPrevious, null); return; } } // Should insert but no invalidation is required. (That's why we need to insert... can't replace an adjacent neighbor) AvlNode <MutablePoint> newNode = new AvlNode <MutablePoint>(); if (insertionSide == Side.Right) { newNode.Parent = this.CurrentNode; newNode.Item = point; this.CurrentNode.Right = newNode; this.AddBalance(newNode.Parent, -1); } else { // Left newNode.Parent = this.CurrentNode; newNode.Item = point; this.CurrentNode.Left = newNode; this.AddBalance(newNode.Parent, 1); } return; } }
/// <summary> /// Removes a node /// </summary> /// <param name="node">node to remove</param> protected void RemoveNode(AvlNode <T> node) { this.count--; AvlNode <T> left = node.Left; AvlNode <T> right = node.Right; if (left == null) { if (right == null) { if (node == this.root) { this.root = null; } else { if (node.Parent.Left == node) { node.Parent.Left = null; this.RemoveBalance(node.Parent, -1); } else if (node.Parent.Right == node) { node.Parent.Right = null; this.RemoveBalance(node.Parent, 1); } } } else { Replace(node, right); this.RemoveBalance(node, 0); } } else if (right == null) { Replace(node, left); this.RemoveBalance(node, 0); } else { AvlNode <T> successor = right; if (successor.Left == null) { AvlNode <T> parent = node.Parent; successor.Parent = parent; successor.Left = left; successor.Balance = node.Balance; left.Parent = successor; if (node == this.root) { this.root = successor; } else { if (parent.Left == node) { parent.Left = successor; } else { parent.Right = successor; } } this.RemoveBalance(successor, 1); } else { while (successor.Left != null) { successor = successor.Left; } AvlNode <T> parent = node.Parent; AvlNode <T> successorParent = successor.Parent; AvlNode <T> successorRight = successor.Right; if (successorParent.Left == successor) { successorParent.Left = successorRight; } else { successorParent.Right = successorRight; } if (successorRight != null) { successorRight.Parent = successorParent; } successor.Parent = parent; successor.Left = left; successor.Balance = node.Balance; successor.Right = right; right.Parent = successor; left.Parent = successor; if (node == this.root) { this.root = successor; } else { if (parent.Left == node) { parent.Left = successor; } else { parent.Right = successor; } } this.RemoveBalance(successorParent, -1); } } }
/// <summary> /// Copies to an array /// </summary> /// <param name="array">The array to copy to</param> /// <param name="index">start point</param> /// <param name="count">number of items to copy</param> public void CopyTo(T[] array, int index, int count) { if (array == null) { throw new ArgumentNullException("'array' can't be null"); } if (index < 0) { throw new ArgumentException("'index' can't be null"); } if (count < 0) { throw new ArgumentOutOfRangeException("'count' should be greater or equal to 0"); } if (index > array.Length || count > array.Length - index) { throw new ArgumentException("The array size is not big enough to get all items"); } if (count == 0) { return; } int indexIter = 0; int indexArray = 0; AvlNode <T> current = this.GetFirstNode(); while (current.GetNextNode() != null) { if (indexIter >= index) { array[indexArray] = current.Item; indexArray++; count--; if (count == 0) { return; } } indexIter++; } /* * foreach (AvlNode<T> node in this.Nodes()) * { * if (indexIter >= index) * { * array[indexArray] = node.Item; * indexArray++; * count--; * if (count == 0) * { * return; * } * } * * indexIter++; * }*/ }
/// <inheritdoc/> public void Clear() { this.root = null; this.count = 0; }
/// <summary> /// Resets the enumerator /// </summary> public void Reset() { this.current = null; }
protected void InvalidateNeighbors(AvlNode <MutablePoint> pointPrevious, AvlNode <MutablePoint> pointNew, AvlNode <MutablePoint> pointNext) { bool invalidPoint; if (pointPrevious != null) { AvlNode <MutablePoint> previousPrevious = pointPrevious.GetPreviousNode(); for (; ;) { if (previousPrevious == null) { break; } invalidPoint = !this.IsPointToTheRightOfOthers(previousPrevious.Item, pointNew.Item, pointPrevious.Item); if (!invalidPoint) { break; } MutablePoint pointPrevPrev = previousPrevious.Item; this.RemoveNode(pointPrevious); pointPrevious = this.GetNode(pointPrevPrev); previousPrevious = pointPrevious.GetPreviousNode(); } } // Invalidate next(s) if (pointNext != null) { AvlNode <MutablePoint> nextNext = pointNext.GetNextNode(); for (; ;) { if (nextNext == null) { break; } invalidPoint = !this.IsPointToTheRightOfOthers(pointNew.Item, nextNext.Item, pointNext.Item); if (!invalidPoint) { break; } MutablePoint pointNextNext = nextNext.Item; this.RemoveNode(pointNext); pointNext = this.GetNode(pointNextNext); nextNext = pointNext.GetNextNode(); } } }