private bool BalanceBranch2(Branch left) { var right = (Branch)TopNode; if (left.KeyCount + right.KeyCount < tree.maxKeyCount) { // Coalesce left: move pivot and right sibling nodes. left.AddKey(GetPivot()); for (int ix1 = 0; ; ++ix1) { left.Add(right.GetChild(ix1)); if (ix1 >= right.KeyCount) { break; } left.AddKey(right.GetKey(ix1)); } left.AdjustWeight(+right.Weight); TiltLeft(+right.Weight); // Pivot must still be removed. return(true); } // Branch underflow? if (tree.IsUnderflow(left.ChildCount)) { // Balance branches to keep ratio. Rotate thru the pivot. int shifts = (left.KeyCount + right.KeyCount - 1) / 2 - left.KeyCount; left.AddKey(GetPivot()); int delta = 0; for (int ix2 = 0; ; ++ix2) { left.Add(right.GetChild(ix2)); delta += right.GetChild(ix2).Weight; if (ix2 >= shifts) { break; } left.AddKey(right.GetKey(ix2)); } SetPivot(right.GetKey(shifts)); right.Remove(0, shifts + 1); left.AdjustWeight(+delta); right.AdjustWeight(-delta); TiltLeft(delta); } return(false); }
// Leaf or branch has been split so insert the new anchor into a branch. public void Promote(T key, Node newNode, bool isAppend) { for (;;) { if (Height == 1) { // Graft new root. Debug.Assert(tree.root == TopNode); tree.root = new Branch(tree.maxKeyCount, TopNode, TopNode.Weight + newNode.Weight); ((Branch)tree.root).Add(key, newNode); break; } Pop(); var branch = (Branch)TopNode; int branchIndex = TopIndex; if (branch.KeyCount < tree.maxKeyCount) { // Typical case where branch has room. branch.InsertKey(branchIndex, key); branch.Insert(branchIndex + 1, newNode); break; } // Branch is full so right split a new branch. var newBranch = new Branch(tree.maxKeyCount); int splitIndex = isAppend ? branch.KeyCount - 1 : (branch.KeyCount + 1) / 2; if (branchIndex < splitIndex) { // Split branch with left-side insert. for (int ix = splitIndex; ; ++ix) { newBranch.AdjustWeight(+branch.GetChild(ix).Weight); if (ix >= branch.KeyCount) { newBranch.Add(branch.GetChild(ix)); break; } newBranch.Add(branch.GetKey(ix), branch.GetChild(ix)); } T newPromotion = branch.GetKey(splitIndex - 1); branch.Truncate(splitIndex - 1); branch.InsertKey(branchIndex, key); branch.Insert(branchIndex + 1, newNode); key = newPromotion; branch.AdjustWeight(-newBranch.Weight); } else { // Split branch with right-side insert (or cascade promote). int leftIndex = splitIndex; newBranch.AdjustWeight(newNode.Weight); if (branchIndex > splitIndex) { for (;;) { ++leftIndex; newBranch.Add(branch.GetChild(leftIndex)); newBranch.AdjustWeight(+branch.GetChild(leftIndex).Weight); if (leftIndex >= branchIndex) { break; } newBranch.AddKey(branch.GetKey(leftIndex)); } newBranch.AddKey(key); key = branch.GetKey(splitIndex); } newBranch.Add(newNode); while (leftIndex < branch.KeyCount) { newBranch.AddKey(branch.GetKey(leftIndex)); ++leftIndex; newBranch.Add(branch.GetChild(leftIndex)); newBranch.AdjustWeight(+branch.GetChild(leftIndex).Weight); } branch.Truncate(splitIndex); branch.AdjustWeight(-newBranch.Weight); } newNode = newBranch; } }