Пример #1
0
        /// <summary>
        /// Fixes this node by combining parent entry downwards.
        /// </summary>
        void FixByCombine(int targetParentIndex,
                          TreeNode <K, V> leftChild, TreeNode <K, V> rightChild, TreeNode <K, V> parent)
        {
            // Move the entry at targetParentIndex from parent to left child.
            leftChild.entries.Add(parent.GetEntry(targetParentIndex));

            // Move all elements in the right child to the left child.
            leftChild.entries.AddRange(rightChild.entries);
            leftChild.childrenIds.AddRange(rightChild.childrenIds);
            // Update parent of the children moved from right child.
            for (int i = 0; i < rightChild.childrenIds.Count; i++)
            {
                var childNode = nodeManager.Find(rightChild.childrenIds[i]);
                childNode.parentId = leftChild.id;
                nodeManager.MarkAsChanged(childNode);
            }

            // Remove the entry at targetParentIndex and rightChild node from parent.
            parent.entries.RemoveAt(targetParentIndex);
            parent.childrenIds.RemoveAt(targetParentIndex + 1);
            // Node no longer used.
            nodeManager.Delete(rightChild);

            // If the parent node is a root and no longer has an entry
            if (parent.parentId == 0 && parent.EntryCount == 0)
            {
                // Make the left child root
                leftChild.parentId = 0;
                nodeManager.MarkAsChanged(leftChild);
                nodeManager.MakeRoot(leftChild);
                nodeManager.Delete(parent);
            }
            // If the parent node is not a root and doesn't have the minimum entry count
            else if (parent.parentId != 0 && parent.EntryCount < nodeManager.MinEntriesPerNode)
            {
                nodeManager.MarkAsChanged(leftChild);
                nodeManager.MarkAsChanged(parent);
                // Fix the parent node.
                parent.FixNode();
            }
            // Else, just finalize.
            else
            {
                nodeManager.MarkAsChanged(leftChild);
                nodeManager.MarkAsChanged(parent);
            }
        }
Пример #2
0
        //
        // Private Methods
        //

        /// <summary>
        /// Rebalance this node after an element has been removed causing it to underflow
        /// </summary>
        void Rebalance()
        {
            // If the deficient node's right sibling exists and has more
            // than the minimum number of elements, then rotate left
            var indexInParent = IndexInParent();
            var parent        = nodeManager.Find(parentId);
            var rightSibling  = ((indexInParent + 1) < parent.ChildrenNodeCount) ? parent.GetChildNode(indexInParent + 1) : null;

            if ((rightSibling != null) && (rightSibling.EntriesCount > nodeManager.MinEntriesPerNode))
            {
                // Copy the separator from the parent to the end of the deficient node
                // (the separator moves down; the deficient node now has the minimum number of elements)
                entries.Add(parent.GetEntry(indexInParent));

                // Replace the separator in the parent with the first element of the right sibling
                // (right sibling loses one node but still has at least the minimum number of elements)
                parent.entries[indexInParent] = rightSibling.entries[0];
                rightSibling.entries.RemoveAt(0);

                // Move the first child reference from right sibling to me.
                if (false == rightSibling.IsLeaf)
                {
                    // First, update parentId of the child that will be moved
                    var n = nodeManager.Find(rightSibling.childrenIds[0]);
                    n.parentId = this.id;
                    nodeManager.MarkAsChanged(n);
                    // Then move it
                    childrenIds.Add(rightSibling.childrenIds[0]);
                    rightSibling.childrenIds.RemoveAt(0);
                }

                // The tree is now balanced
                nodeManager.MarkAsChanged(this);
                nodeManager.MarkAsChanged(parent);
                nodeManager.MarkAsChanged(rightSibling);
                return;
            }

            // Otherwise, if the deficient node's left sibling exists and has more
            // than the minimum number of elements, then rotate right
            var leftSibling = ((indexInParent - 1) >= 0) ? parent.GetChildNode(indexInParent - 1) : null;

            if ((leftSibling != null) && (leftSibling.EntriesCount > nodeManager.MinEntriesPerNode))
            {
                // Copy the separator from the parent to the start of the deficient node
                // (the separator moves down; deficient node now has the minimum number of elements)
                entries.Insert(0, parent.GetEntry(indexInParent - 1));

                // Replace the separator in the parent with the last element
                // of the left sibling (left sibling loses one node but still has
                // at least the minimum number of elements)
                parent.entries[indexInParent - 1] = leftSibling.entries[leftSibling.entries.Count - 1];
                leftSibling.entries.RemoveAt(leftSibling.entries.Count - 1);

                // Move the last child reference from the left sibing to me.
                // First, update parentId of the child that will be moved.
                if (false == IsLeaf)
                {
                    var n = nodeManager.Find(leftSibling.childrenIds[leftSibling.childrenIds.Count - 1]);
                    n.parentId = this.id;
                    nodeManager.MarkAsChanged(n);
                    // Then move it
                    childrenIds.Insert(0, leftSibling.childrenIds[leftSibling.childrenIds.Count - 1]);
                    leftSibling.childrenIds.RemoveAt(leftSibling.childrenIds.Count - 1);
                }

                // The tree is now balanced;
                nodeManager.MarkAsChanged(this);
                nodeManager.MarkAsChanged(parent);
                nodeManager.MarkAsChanged(leftSibling);
                return;
            }

            // Otherwise, if both immediate siblings have only the minimum number of elements,
            // then merge with a sibling sandwiching their separator taken off from their parent
            var leftChild            = rightSibling != null ? this : leftSibling;
            var rightChild           = rightSibling != null ? rightSibling : this;
            var seperatorParentIndex = rightSibling != null ? indexInParent : (indexInParent - 1);

            // Step 1:
            // Copy the separator to the end of the left node (the left node may be the
            // deficient node or it may be the sibling with the minimum number of elements)
            leftChild.entries.Add(parent.GetEntry(seperatorParentIndex));

            // Move all elements from the right node to the left
            // node (the left node now has the maximum number of elements, and the right node – empty)
            leftChild.entries.AddRange(rightChild.entries);
            leftChild.childrenIds.AddRange(rightChild.childrenIds);
            // Update parent id of the children that has been moved from rightChild to leftChild
            foreach (var id in rightChild.childrenIds)
            {
                var n = nodeManager.Find(id);
                n.parentId = leftChild.id;
                nodeManager.MarkAsChanged(n);;
            }

            // Remove the separator from the parent along with its
            // empty right child (the parent loses an element)
            parent.entries.RemoveAt(seperatorParentIndex);
            parent.childrenIds.RemoveAt(seperatorParentIndex + 1);
            nodeManager.Delete(rightChild);

            // If the parent is the root and now has no elements,
            // then free it and make the merged node the new root (tree becomes shallower)
            if (parent.parentId == 0 && parent.EntriesCount == 0)
            {
                leftChild.parentId = 0;
                nodeManager.MarkAsChanged(leftChild); // Changed left one
                nodeManager.MakeRoot(leftChild);
                nodeManager.Delete(parent);           // Deleted parent
            }
            // Otherwise, if the parent has fewer than
            // the required number of elements, then rebalance the parent
            else if ((parent.parentId != 0) && (parent.EntriesCount < nodeManager.MinEntriesPerNode))
            {
                nodeManager.MarkAsChanged(leftChild);  // Changed left one
                nodeManager.MarkAsChanged(parent);     // Changed parent
                parent.Rebalance();
            }
            else
            {
                nodeManager.MarkAsChanged(leftChild);  // Changed left one
                nodeManager.MarkAsChanged(parent);     // Changed parent
            }
        }