private void RotateLL() { TTreeNode <TItem, TNode> left = Left; TTreeNode <TItem, TNode> leftsRight = left.Right; if (Parent != null) { if (Parent.Left == this) { Parent.Left = (TNode)left; } else { Parent.Right = (TNode)left; } } left.Parent = Parent; left.Right = (TNode)this; Parent = (TNode)left; Left = (TNode)leftsRight; if (leftsRight != null) { leftsRight.Parent = (TNode)this; } if (left.Parent == null) { Tree.RootNode = (TNode)left; } UpdateHeight(HeightUpdateType.UpdateAllUpwards); }
private void RotateRR() { TTreeNode <TItem, TNode> nodeRight = Right; TTreeNode <TItem, TNode> nodeRightsLeft = nodeRight.Left; if (Parent != null) { if (Parent.Left == this) { Parent.Left = (TNode)nodeRight; } else { Parent.Right = (TNode)nodeRight; } } nodeRight.Parent = Parent; nodeRight.Left = (TNode)this; Parent = (TNode)nodeRight; Right = (TNode)nodeRightsLeft; if (nodeRightsLeft != null) { nodeRightsLeft.Parent = (TNode)this; } if (nodeRight.Parent == null) { Tree.RootNode = (TNode)nodeRight; } UpdateHeight(HeightUpdateType.UpdateAllUpwards); }
public SearchResult(TItem value, TTreeNode <TItem, TNode> node, int index) { Value = value; Node = node; Index = index; }
/// <summary> /// Adds the specified item. /// </summary> /// <param name="item">The item.</param> /// <returns>True if the item was added or false if it already existed and was not </returns> public bool AddItem(TItem item) { bool isBoundingNode; int comparedToFirst = 0; //Is this the bounding node for the new item? If the node is empty it is considered to be the bounding node. if (ItemCount == 0) { isBoundingNode = true; } else { //Compare the item to be inserted to the first item in the data comparedToFirst = item.CompareTo(m_data[0]); isBoundingNode = ((comparedToFirst >= 0) && (item.CompareTo(m_data[ItemCount - 1]) <= 0)); } if (isBoundingNode) { //Is there space in this node? if (ItemCount < m_data.Length) { //This is the bounding node, add the new item return(InsertInCurrentNode(item, ShiftType.NoShift)); } else { //Copy the old minimum. This current item will be inserted into this node TItem oldMinimum = m_data[0]; if (!InsertInCurrentNode(item, ShiftType.FullShiftToLeft)) { return(false); } //Add the old minimum if (Left == null) { //There is no left child, so create it Left = CreateChild(oldMinimum); UpdateHeight(HeightUpdateType.CurrentLevelOnly); Rebalance(BalanceType.StopAfterFirstRotate); return(true); } else { //Add the old minimum to the left child return(Left.AddItem(oldMinimum)); } } } else { //If the item is less than the minimum and there is a left node, follow it if ((Left != null) && (comparedToFirst < 0)) { return(Left.AddItem(item)); } //If the item is less than the maximum and there is a right node, follow it if ((Right != null) && (comparedToFirst > 0)) { return(Right.AddItem(item)); } //If we are here then, there is no bounding node for this value. //Is there place in this node if (ItemCount < m_data.Length) { //There is place in this node so add the new value. However since this value // must be the new minimum or maximum (otherwise it would have found a bounding // node) dont call InsertInCurrentNode which would do a binary search to find // an insert location. Rather check for min/max and add it here. if (comparedToFirst > 0) { //The item is greater than the minimum, therfore it must be the new maximum. // Add it to the end of the array m_data[ItemCount] = item; } else { //The item is the new miminum. Shift the array up and insert it. Array.Copy(m_data, 0, m_data, 1, ItemCount); m_data[0] = item; } ItemCount++; } else { TTreeNode <TItem, TNode> newChild = CreateChild(item); //Add it as the the left or the right child if (comparedToFirst < 0) { Left = (TNode)newChild; } else { Right = (TNode)newChild; } UpdateHeight(HeightUpdateType.UpdateAllUpwards); Rebalance(BalanceType.StopAfterFirstRotate); return(true); } } return(true); }
public bool Remove(TItem item) { SearchResult <TItem, TNode> searchResult = SearchFor(item); if (searchResult == null) { return(false); } TTreeNode <TItem, TNode> rebalanceFrom = searchResult.Node; //If the remove will not cause an underflow then, delete the value and stop if (searchResult.Node.ItemCount > searchResult.Node.m_minimum) { DeleteFoundValue(searchResult); return(true); } if (searchResult.Node.IsInternal) { //Shift the array to the right "delete" // This is faster than calling DeleteFoundValue() because now there is no need to shift // the array a second time to make space for the greatest lower bound if (searchResult.Index > 0) { Array.Copy(searchResult.Node.m_data, searchResult.Index - 1, searchResult.Node.m_data, searchResult.Index, searchResult.Node.m_data.Length - 1 - searchResult.Index); } //Insert the greatest lower bound m_data[0] = searchResult.Node.Left.CutGreatestLowerBound(); } else //This is a leaf or half-leaf so just delete the value (leaves and half-leaves are permitted to underflow) { DeleteFoundValue(searchResult); //If this is a half leaf and it can be merged with a leaf, then combine if (searchResult.Node.IsHalfLeaf) { var child = searchResult.Node.Left ?? searchResult.Node.Right; //If all the child items can fit into this node if (searchResult.Node.ItemCount + child.ItemCount <= MaxItems) { //TODO consider not looping - the child is sorted, insert all the items at once, either at the begining or at the end (left/right) for (int i = 0; i < child.ItemCount; ++i) { searchResult.Node.InsertInCurrentNode(child.m_data[i], ShiftType.NoShift); } //Remove the child searchResult.Node.Left = searchResult.Node.Right = null; searchResult.Node.m_height = 0; } } else //Is leaf { if (searchResult.Node.ItemCount != 0) { //This is a non-empty leaf. Nothing more to do return(true); } else { //The node is empty. So, unles this is the root, remove the node from its parent. if (searchResult.Node.Parent != null) { if (searchResult.Node.Parent.Left == searchResult.Node) { searchResult.Node.Parent.Left = null; } else { searchResult.Node.Parent.Right = null; } //The current node has been deleted, so rebalance from its parent rebalanceFrom = rebalanceFrom.Parent; } } } } rebalanceFrom.Rebalance(BalanceType.StopAfterEvenBalanceFound); return(true); }