/// <summary> /// Tries moving to next entry by ascending order. /// </summary> bool Ascend() { curIndex++; if (curNode.IsLeaf) { while (true) { // If a valid entry in node was found, return it. if (curIndex < curNode.EntryCount) { curEntry = curNode.GetEntry(curIndex); return(true); } // Else if no valid entry in node and there is a parent node else if (curNode.ParentId != 0) { // Adjust index to point to current node in parent. curIndex = curNode.IndexInParent(); // Set target node one level up. curNode = nodeManager.Find(curNode.ParentId); // Validate parent if (curIndex < 0 || curNode == null) { throw new Exception("An error in BTree was detected."); } } // No more parent nodes and valid entries. We should just finish off here else { curEntry = null; isFinished = true; return(false); } } } else { do { // Get the next child node on first iteration, // or the first child node on further iterations. curNode = curNode.GetChildNode(curIndex); // Reset index to 0 to indicate first child and entry in the newly found node. curIndex = 0; // Validate new node if (curNode == null) { throw new Exception("An error in BTree was detected."); } }while(!curNode.IsLeaf); curEntry = curNode.GetEntry(curIndex); return(true); } }
bool MoveForward() { // Leaf node, either move right or up if (currentNode.IsLeaf) { // First, move right currentEntry++; while (true) { // If currentEntry is valid // then we are done here. if (currentEntry < currentNode.EntriesCount) { current = currentNode.GetEntry(currentEntry); return(true); } // If can't move right then move up else if (currentNode.ParentId != 0) { currentEntry = currentNode.IndexInParent(); currentNode = nodeManager.Find(currentNode.ParentId); // Validate move up result if ((currentEntry < 0) || (currentNode == null)) { throw new Exception("Something gone wrong with the BTree"); } } // If can't move up when we are done iterating else { current = null; doneIterating = true; return(false); } } } // Parent node, always move right down else { currentEntry++; // Increase currentEntry, this make firstCall to nodeManager.Find // to return the right node, but does not affect subsequence calls do { currentNode = currentNode.GetChildNode(currentEntry); currentEntry = 0; } while (false == currentNode.IsLeaf); current = currentNode.GetEntry(currentEntry); return(true); } }
/// <summary> /// Splits this node to left and right nodes. /// </summary> public void Split(out TreeNode <K, V> leftNode, out TreeNode <K, V> rightNode) { Debug.Assert(IsOverflow, "This node is not yet overflowing."); bool isLeaf = IsLeaf; var halfCount = nodeManager.MinEntriesPerNode; var middleEntry = entries[halfCount]; // Get larger entries and children for new node. var largeEntries = new Tuple <K, V> [halfCount]; uint[] largeChildren = null; // Copy larger entries to newer node. entries.CopyTo(halfCount + 1, largeEntries, 0, halfCount); // Copy child node ids if not a leaf. if (!isLeaf) { largeChildren = new uint[halfCount + 1]; childrenIds.CopyTo(halfCount + 1, largeChildren, 0, halfCount); } // Create larger node var largeNode = nodeManager.Create(largeEntries, largeChildren); // All child nodes moved to newer node must refresh their parentId. if (!isLeaf) { for (int i = 0; i < largeChildren.Length; i++) { nodeManager.Find(largeChildren[i]).ParentId = largeNode.id; } } // Remove all large entries and children ids from this node. // Entries list must also remove the middle entry because it will go to the parent node. entries.RemoveRange(halfCount); if (!isLeaf) { childrenIds.RemoveRange(halfCount + 1); } // Try getting parent node var parentNode = parentId == 0 ? null : nodeManager.Find(parentId); // If no parent, create a new parent node with the middle entry if (parentNode == null) { parentNode = nodeManager.CreateNewRoot( middleEntry.Item1, middleEntry.Item2, id, largeNode.id ); // Reassign parent id this.ParentId = parentNode.id; largeNode.ParentId = parentNode.id; } // Move the middle element to the parent node. else { int insertIndex = 0; parentNode.InsertAsParent( middleEntry.Item1, middleEntry.Item2, id, largeNode.id, out insertIndex ); // Reassign parent id for large node only because this node's already been set. largeNode.ParentId = parentNode.id; // Split parent node if overflowing. if (parentNode.IsOverflow) { Split(); } } // Output nodes leftNode = this; rightNode = largeNode; // Mark this node dirty nodeManager.MarkAsChanged(this); }
// // Public Methods // /// <summary> /// Remove an entry from this instance. /// </summary> public void Remove(int removeAt) { // Validate argument if (false == (removeAt >= 0) && (removeAt < this.entries.Count)) { throw new ArgumentOutOfRangeException(); } // http://webdocs.cs.ualberta.ca/~holte/T26/del-b-tree.html // https://en.wikipedia.org/wiki/B-tree#Deletion // If this is a node leave, flagged entry will be removed if (IsLeaf) { // Step 1: Remove X from the current node. // Being a leaf node there are no subtrees to worry about. entries.RemoveAt(removeAt); nodeManager.MarkAsChanged(this); // If the removal does not cause underflow then we are done here if ((EntriesCount >= nodeManager.MinEntriesPerNode) || (parentId == 0)) { return; } // Otherwise, rebalance this node else { Rebalance(); } } // If the value to be deleted does not occur in a leaf, // we replace it with the largest value in its left subtree // and then proceed to delete that value from the node that // originally contained it else { // Grab the largest entry on the left subtree var leftSubTree = nodeManager.Find(this.childrenIds[removeAt]); TreeNode <K, V> largestNode; int largestIndex; leftSubTree.FindLargest(out largestNode, out largestIndex); var replacementEntry = largestNode.GetEntry(largestIndex); // REplace it this.entries[removeAt] = replacementEntry; nodeManager.MarkAsChanged(this); // Remove it from the node we took it from largestNode.Remove(largestIndex); } }