private bool RemoveItemFromNode(BPlusNode <TItem> node, TItem itemToDelete, int itemIndexInNode) { // if leaf, just remove it from the list of entries (we're guaranteed to have // at least "degree" # of entries, to BTree property is maintained if (node.IsLeaf) { node.RemoveItem(itemIndexInNode); return(true); } var predecessorChild = node.Nodes[itemIndexInNode]; if (predecessorChild.Items.Count >= _degree) { var predecessor = RemovePredecessor(predecessorChild); node.Items[itemIndexInNode] = predecessor; } else { var successorChild = node.Nodes[itemIndexInNode + 1]; if (successorChild.Items.Count >= _degree) { var successor = RemoveSuccessor(predecessorChild); node.Items[itemIndexInNode] = successor; } else { predecessorChild.InsertItem(node.Items[itemIndexInNode]); predecessorChild.InsertItems(successorChild.Items); predecessorChild.InsertNodes(successorChild.Nodes); node.RemoveItem(itemIndexInNode); node.RemoveNode(itemIndexInNode + 1); return(RemoveInternal(predecessorChild, itemToDelete)); } } return(false); }
private TItem RemoveSuccessor(BPlusNode <TItem> node) { while (true) { if (node.IsLeaf) { var result = node.Items[0]; node.RemoveItem(0); return(result); } node = node.Nodes[0]; } }
private TItem RemovePredecessor(BPlusNode <TItem> node) { while (true) { if (node.IsLeaf) { var result = node.Items[node.Items.Count - 1]; node.RemoveItem(node.Items.Count - 1); return(result); } node = node.Nodes[node.Nodes.Count - 1]; } }
private bool RemoveItemFromSubTree(BPlusNode <TItem> parentNode, TItem itemToDelete, int subTreeIndex) { var childNode = parentNode.Nodes[subTreeIndex]; // node has reached min # of entries, and removing any from it will break the btree property, // so this block makes sure that the "child" has at least "degree" # of nodes by moving an // entry from a sibling node or merging nodes if (childNode.HasReachedMinSize) { var leftIndex = subTreeIndex - 1; var leftSibling = subTreeIndex > 0 ? parentNode.Nodes[leftIndex] : null; var rightIndex = subTreeIndex + 1; var rightSibling = subTreeIndex < parentNode.Nodes.Count - 1 ? parentNode.Nodes[rightIndex] : null; if (leftSibling != null && leftSibling.Items.Count > _degree - 1) { // left sibling has a node to spare, so this moves one node from left sibling // into parent's node and one node from parent into this current node ("child") childNode.InsertItem(0, parentNode.Items[subTreeIndex]); parentNode.Items[subTreeIndex] = leftSibling.Items[leftSibling.Items.Count - 1]; leftSibling.RemoveItem(leftSibling.Items.Count - 1); if (!leftSibling.IsLeaf) { childNode.InsertNode(0, leftSibling.Nodes[leftSibling.Nodes.Count - 1]); leftSibling.RemoveNode(leftSibling.Nodes.Count - 1); } } else if (rightSibling != null && rightSibling.Items.Count > _degree - 1) { // right sibling has a node to spare, so this moves one node from right sibling // into parent's node and one node from parent into this current node ("child") childNode.InsertItem(parentNode.Items[subTreeIndex]); parentNode.Items[subTreeIndex] = rightSibling.Items[0]; rightSibling.RemoveItem(0); if (!rightSibling.IsLeaf) { childNode.InsertNode(rightSibling.Nodes[0]); rightSibling.RemoveNode(0); } } else { // this block merges either left or right sibling into the current node "child" if (leftSibling != null) { childNode.InsertItem(0, parentNode.Items[subTreeIndex]); var oldEntries = childNode.Items; childNode.Items = leftSibling.Items; childNode.InsertItems(oldEntries); if (!leftSibling.IsLeaf) { var oldChildren = childNode.Nodes; childNode.Nodes = leftSibling.Nodes; childNode.InsertNodes(oldChildren); } parentNode.RemoveNode(leftIndex); parentNode.RemoveItem(subTreeIndex); } else { childNode.InsertItem(parentNode.Items[subTreeIndex]); childNode.InsertItems(rightSibling.Items); if (!rightSibling.IsLeaf) { childNode.InsertNodes(rightSibling.Nodes); } parentNode.RemoveNode(rightIndex); parentNode.RemoveItem(subTreeIndex); } } } // at this point, we know that "child" has at least "degree" nodes, so we can // move on - this guarantees that if any node needs to be removed from it to // guarantee BTree's property, we will be fine with that return(RemoveInternal(childNode, itemToDelete)); }