Exemplo n.º 1
0
        // Delete element already found at path.
        private void Delete(TreePath <TKey, TValue> path)
        {
            int leafIndex            = path.TopNodeIndex;
            Leaf <TKey, TValue> leaf = (Leaf <TKey, TValue>)path.TopNode;

            leaf.Remove(leafIndex);
            --Count;

            if (leafIndex == 0)
            {
                if (leaf.KeyCount != 0)
                {
                    path.SetPivot(path.TopNode.GetKey(0));
                }
                else
                {
                    Debug.Assert(leaf.RightLeaf == null, "only the rightmost leaf should ever be emptied");

                    // Leaf is empty.  Prune it unless it is the only leaf in the tree.
                    Leaf <TKey, TValue> leftLeaf = (Leaf <TKey, TValue>)path.GetLeftNode();
                    if (leftLeaf != null)
                    {
                        leftLeaf.RightLeaf = leaf.RightLeaf;
                        Demote(path);
                    }

                    return;
                }
            }

            // Leaf underflow?
            if (leaf.KeyCount < leaf.KeyCapacity / 2)
            {
                Leaf <TKey, TValue> rightLeaf = leaf.RightLeaf;
                if (rightLeaf != null)
                {
                    if (leaf.KeyCount + rightLeaf.KeyCount > leaf.KeyCapacity)
                    {
                        // Balance leaves by shifting pairs from right leaf.
                        int shifts = leaf.KeyCapacity - (leaf.KeyCount + rightLeaf.KeyCount - 1) / 2;
                        leaf.Add(rightLeaf, 0, shifts);
                        rightLeaf.Remove(0, shifts);
                        path.TraverseRight();
                        path.SetPivot(path.TopNode.GetKey(0));
                    }
                    else
                    {
                        // Coalesce right leaf to current leaf and prune right leaf.
                        leaf.Add(rightLeaf, 0, rightLeaf.KeyCount);
                        leaf.RightLeaf = rightLeaf.RightLeaf;
                        path.TraverseRight();
                        Demote(path);
                    }
                }
            }
        }
Exemplo n.º 2
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;
            }
        }