Ejemplo n.º 1
0
        // 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;
            }
        }
Ejemplo n.º 2
0
        // 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;
            }
        }