// Leaf has been emptied, now non-lazy delete its pivot. private void Demote(TreePath <TKey, TValue> path) { for (;;) { Debug.Assert(path.Height > 0); path.Pop(); Branch <TKey> branch = (Branch <TKey>)path.TopNode; if (path.TopNodeIndex == 0) { if (branch.KeyCount == 0) { // Cascade when rightmost branch is empty. continue; } // Rotate pivot for first child. TKey pivot0 = branch.GetKey(0); branch.RemoveKey(0); branch.RemoveChild(0); path.SetPivot(pivot0); } else { // Typical branch pivot delete. branch.RemoveKey(path.TopNodeIndex - 1); branch.RemoveChild(path.TopNodeIndex); } Branch <TKey> right = (Branch <TKey>)path.TraverseRight(); if (right == null) { if (branch == root && branch.KeyCount == 0) { // Prune the empty root. Branch <TKey> newRoot = branch.FirstChild as Branch <TKey>; if (newRoot != null) { root = (Branch <TKey>)branch.FirstChild; --height; } } return; } if (branch.KeyCount + right.KeyCount < branch.KeyCapacity) { // Coalesce left: move pivot and right sibling nodes. branch.AddKey(path.GetPivot()); for (int i = 0;; ++i) { branch.Add(right.GetChild(i)); if (i >= right.KeyCount) { break; } branch.AddKey(right.GetKey(i)); } // Cascade demotion. continue; } // Branch underflow? if (branch.KeyCount < branch.KeyCapacity / 2) { int shifts = (right.KeyCount - branch.KeyCount) / 2 - 1; // Balance branches to keep ratio. Rotate thru the pivot. branch.AddKey(path.GetPivot()); // Shift pairs from right sibling. for (int rightIndex = 0;; ++rightIndex) { branch.Add(right.GetChild(rightIndex)); if (rightIndex >= shifts) { break; } branch.AddKey(right.GetKey(rightIndex)); } path.SetPivot(right.GetKey(shifts)); right.Remove(0, shifts + 1); } return; } }
// Leaf has been split so insert the new anchor into a branch. private void Promote(TreePath <TKey, TValue> path, TKey key, Node <TKey> newNode) { for (;;) { if (path.Height == 1) { Debug.Assert(root == path.TopNode); // Graft new root. root = new Branch <TKey>(path.TopNode, Order); root.Add(key, newNode); ++height; break; } path.Pop(); Branch <TKey> branch = (Branch <TKey>)path.TopNode; int branchIndex = path.TopNodeIndex; if (branch.NotFull) { // Typical case where branch has room. branch.InsertKey(branchIndex, key); branch.Insert(branchIndex + 1, newNode); break; } // Right split an overflowing branch. Branch <TKey> newBranch = new Branch <TKey>(branch); int halfway = (branch.KeyCount + 1) / 2; if (branchIndex < halfway) { // Split with left-side insert. for (int i = halfway;; ++i) { if (i >= branch.KeyCount) { newBranch.Add(branch.GetChild(i)); break; } newBranch.Add(branch.GetKey(i), branch.GetChild(i)); } TKey newPromotion = branch.GetKey(halfway - 1); branch.Truncate(halfway - 1); branch.InsertKey(branchIndex, key); branch.Insert(branchIndex + 1, newNode); key = newPromotion; } else { // Split branch with right-side insert (or cascade promote). int moveIndex = halfway; if (branchIndex > halfway) { for (;;) { ++moveIndex; newBranch.Add(branch.GetChild(moveIndex)); if (moveIndex >= branchIndex) { break; } newBranch.AddKey(branch.GetKey(moveIndex)); } newBranch.AddKey(key); key = branch.GetKey(halfway); } newBranch.Add(newNode); while (moveIndex < branch.KeyCount) { newBranch.AddKey(branch.GetKey(moveIndex)); ++moveIndex; newBranch.Add(branch.GetChild(moveIndex)); } branch.Truncate(halfway); } newNode = newBranch; } }