Example #1
0
        private void InsertNonFull(BtreeNode <TK, TP> BtreeNode, TK newKey, TP newPointer)
        {
            int positionToInsert = BtreeNode.Entries.TakeWhile(entry => newKey.CompareTo(entry.Key) >= 0).Count();

            // leaf BtreeNode
            if (BtreeNode.IsLeaf)
            {
                BtreeNode.Entries.Insert(positionToInsert, new Entry <TK, TP>()
                {
                    Key = newKey, Pointer = newPointer
                });
                return;
            }

            // non-leaf
            BtreeNode <TK, TP> child = BtreeNode.Children[positionToInsert];

            if (child.HasReachedMaxEntries)
            {
                this.SplitChild(BtreeNode, positionToInsert, child);
                if (newKey.CompareTo(BtreeNode.Entries[positionToInsert].Key) > 0)
                {
                    positionToInsert++;
                }
            }

            this.InsertNonFull(BtreeNode.Children[positionToInsert], newKey, newPointer);
        }
Example #2
0
        /// <summary>
        /// Helper method that search for a key in a given BTree.
        /// </summary>
        /// <param name="BtreeNode">BtreeNode used to start the search.</param>
        /// <param name="key">Key to be searched.</param>
        /// <returns>Entry object with key information if found, null otherwise.</returns>
        private Entry <TK, TP> SearchInternal(BtreeNode <TK, TP> BtreeNode, TK key)
        {
            int i = BtreeNode.Entries.TakeWhile(entry => key.CompareTo(entry.Key) > 0).Count();

            if (i < BtreeNode.Entries.Count && BtreeNode.Entries[i].Key.CompareTo(key) == 0)
            {
                return(BtreeNode.Entries[i]);
            }

            return(BtreeNode.IsLeaf ? null : this.SearchInternal(BtreeNode.Children[i], key));
        }
Example #3
0
        /// <summary>
        /// Helper method that deletes a successor key (i.e. leftmost key) for a given BtreeNode.
        /// </summary>
        /// <param name="BtreeNode">BtreeNode for which the successor will be deleted.</param>
        /// <returns>Successor entry that got deleted.</returns>
        private Entry <TK, TP> DeleteSuccessor(BtreeNode <TK, TP> BtreeNode)
        {
            if (BtreeNode.IsLeaf)
            {
                var result = BtreeNode.Entries[0];
                BtreeNode.Entries.RemoveAt(0);
                return(result);
            }

            return(this.DeletePredecessor(BtreeNode.Children.First()));
        }
Example #4
0
        /// <summary>
        /// Helper method that deletes a predecessor key (i.e. rightmost key) for a given BtreeNode.
        /// </summary>
        /// <param name="BtreeNode">BtreeNode for which the predecessor will be deleted.</param>
        /// <returns>Predecessor entry that got deleted.</returns>
        private Entry <TK, TP> DeletePredecessor(BtreeNode <TK, TP> BtreeNode)
        {
            if (BtreeNode.IsLeaf)
            {
                var result = BtreeNode.Entries[BtreeNode.Entries.Count - 1];
                BtreeNode.Entries.RemoveAt(BtreeNode.Entries.Count - 1);
                return(result);
            }

            return(this.DeletePredecessor(BtreeNode.Children.Last()));
        }
Example #5
0
        /// <summary>
        /// Internal method to delete keys from the BTree
        /// </summary>
        /// <param name="BtreeNode">BtreeNode to use to start search for the key.</param>
        /// <param name="keyToDelete">Key to be deleted.</param>
        private void DeleteInternal(BtreeNode <TK, TP> BtreeNode, TK keyToDelete)
        {
            int i = BtreeNode.Entries.TakeWhile(entry => keyToDelete.CompareTo(entry.Key) > 0).Count();

            // found key in BtreeNode, so delete if from it
            if (i < BtreeNode.Entries.Count && BtreeNode.Entries[i].Key.CompareTo(keyToDelete) == 0)
            {
                this.DeleteKeyFromBtreeNode(BtreeNode, keyToDelete, i);
                return;
            }

            // delete key from subtree
            if (!BtreeNode.IsLeaf)
            {
                this.DeleteKeyFromSubtree(BtreeNode, keyToDelete, i);
            }
        }
Example #6
0
        /// <summary>
        /// Helper method that splits a full BtreeNode into two BtreeNodes.
        /// </summary>
        /// <param name="parentBtreeNode">Parent BtreeNode that contains BtreeNode to be split.</param>
        /// <param name="BtreeNodeToBeSplitIndex">Index of the BtreeNode to be split within parent.</param>
        /// <param name="BtreeNodeToBeSplit">BtreeNode to be split.</param>
        private void SplitChild(BtreeNode <TK, TP> parentBtreeNode, int BtreeNodeToBeSplitIndex, BtreeNode <TK, TP> BtreeNodeToBeSplit)
        {
            var newBtreeNode = new BtreeNode <TK, TP>(this.Degree);

            parentBtreeNode.Entries.Insert(BtreeNodeToBeSplitIndex, BtreeNodeToBeSplit.Entries[this.Degree - 1]);
            parentBtreeNode.Children.Insert(BtreeNodeToBeSplitIndex + 1, newBtreeNode);

            newBtreeNode.Entries.AddRange(BtreeNodeToBeSplit.Entries.GetRange(this.Degree, this.Degree - 1));

            // remove also Entries[this.Degree - 1], which is the one to move up to the parent
            BtreeNodeToBeSplit.Entries.RemoveRange(this.Degree - 1, this.Degree);

            if (!BtreeNodeToBeSplit.IsLeaf)
            {
                newBtreeNode.Children.AddRange(BtreeNodeToBeSplit.Children.GetRange(this.Degree, this.Degree));
                BtreeNodeToBeSplit.Children.RemoveRange(this.Degree, this.Degree);
            }
        }
Example #7
0
        /// <summary>
        /// Inserts a new key associated with a pointer in the BTree. This
        /// operation splits BtreeNodes as required to keep the BTree properties.
        /// </summary>
        /// <param name="newKey">Key to be inserted.</param>
        /// <param name="newPointer">Pointer to be associated with inserted key.</param>
        public void Insert(TK newKey, TP newPointer)
        {
            // there is space in the root BtreeNode
            if (!this.Root.HasReachedMaxEntries)
            {
                this.InsertNonFull(this.Root, newKey, newPointer);
                return;
            }

            // need to create new BtreeNode and have it split
            BtreeNode <TK, TP> oldRoot = this.Root;

            this.Root = new BtreeNode <TK, TP>(this.Degree);
            this.Root.Children.Add(oldRoot);
            this.SplitChild(this.Root, 0, oldRoot);
            this.InsertNonFull(this.Root, newKey, newPointer);

            this.Height++;
        }
Example #8
0
        /// <summary>
        /// Helper method that deletes key from a BtreeNode that contains it, be this
        /// BtreeNode a leaf BtreeNode or an internal BtreeNode.
        /// </summary>
        /// <param name="BtreeNode">BtreeNode that contains the key.</param>
        /// <param name="keyToDelete">Key to be deleted.</param>
        /// <param name="keyIndexInBtreeNode">Index of key within the BtreeNode.</param>
        private void DeleteKeyFromBtreeNode(BtreeNode <TK, TP> BtreeNode, TK keyToDelete, int keyIndexInBtreeNode)
        {
            // if leaf, just remove it from the list of entries (we're guaranteed to have
            // at least "degree" # of entries, to BTree property is maintained
            if (BtreeNode.IsLeaf)
            {
                BtreeNode.Entries.RemoveAt(keyIndexInBtreeNode);
                return;
            }

            BtreeNode <TK, TP> predecessorChild = BtreeNode.Children[keyIndexInBtreeNode];

            if (predecessorChild.Entries.Count >= this.Degree)
            {
                Entry <TK, TP> predecessor = this.DeletePredecessor(predecessorChild);
                BtreeNode.Entries[keyIndexInBtreeNode] = predecessor;
            }
            else
            {
                BtreeNode <TK, TP> successorChild = BtreeNode.Children[keyIndexInBtreeNode + 1];
                if (successorChild.Entries.Count >= this.Degree)
                {
                    Entry <TK, TP> successor = this.DeleteSuccessor(predecessorChild);
                    BtreeNode.Entries[keyIndexInBtreeNode] = successor;
                }
                else
                {
                    predecessorChild.Entries.Add(BtreeNode.Entries[keyIndexInBtreeNode]);
                    predecessorChild.Entries.AddRange(successorChild.Entries);
                    predecessorChild.Children.AddRange(successorChild.Children);

                    BtreeNode.Entries.RemoveAt(keyIndexInBtreeNode);
                    BtreeNode.Children.RemoveAt(keyIndexInBtreeNode + 1);

                    this.DeleteInternal(predecessorChild, keyToDelete);
                }
            }
        }
Example #9
0
        /// <summary>
        /// Helper method that deletes a key from a subtree.
        /// </summary>
        /// <param name="parentBtreeNode">Parent BtreeNode used to start search for the key.</param>
        /// <param name="keyToDelete">Key to be deleted.</param>
        /// <param name="subtreeIndexInBtreeNode">Index of subtree BtreeNode in the parent BtreeNode.</param>
        private void DeleteKeyFromSubtree(BtreeNode <TK, TP> parentBtreeNode, TK keyToDelete, int subtreeIndexInBtreeNode)
        {
            BtreeNode <TK, TP> childBtreeNode = parentBtreeNode.Children[subtreeIndexInBtreeNode];

            // BtreeNode has reached min # of entries, and removing any from it will break the btree property,
            // so this block makes sure that the "child" has at least "degree" # of BtreeNodes by moving an
            // entry from a sibling BtreeNode or merging BtreeNodes
            if (childBtreeNode.HasReachedMinEntries)
            {
                int leftIndex = subtreeIndexInBtreeNode - 1;
                BtreeNode <TK, TP> leftSibling = subtreeIndexInBtreeNode > 0 ? parentBtreeNode.Children[leftIndex] : null;

                int rightIndex = subtreeIndexInBtreeNode + 1;
                BtreeNode <TK, TP> rightSibling = subtreeIndexInBtreeNode < parentBtreeNode.Children.Count - 1
                                                ? parentBtreeNode.Children[rightIndex]
                                                : null;

                if (leftSibling != null && leftSibling.Entries.Count > this.Degree - 1)
                {
                    // left sibling has a BtreeNode to spare, so this moves one BtreeNode from left sibling
                    // into parent's BtreeNode and one BtreeNode from parent into this current BtreeNode ("child")
                    childBtreeNode.Entries.Insert(0, parentBtreeNode.Entries[subtreeIndexInBtreeNode]);
                    parentBtreeNode.Entries[subtreeIndexInBtreeNode] = leftSibling.Entries.Last();
                    leftSibling.Entries.RemoveAt(leftSibling.Entries.Count - 1);

                    if (!leftSibling.IsLeaf)
                    {
                        childBtreeNode.Children.Insert(0, leftSibling.Children.Last());
                        leftSibling.Children.RemoveAt(leftSibling.Children.Count - 1);
                    }
                }
                else if (rightSibling != null && rightSibling.Entries.Count > this.Degree - 1)
                {
                    // right sibling has a BtreeNode to spare, so this moves one BtreeNode from right sibling
                    // into parent's BtreeNode and one BtreeNode from parent into this current BtreeNode ("child")
                    childBtreeNode.Entries.Add(parentBtreeNode.Entries[subtreeIndexInBtreeNode]);
                    parentBtreeNode.Entries[subtreeIndexInBtreeNode] = rightSibling.Entries.First();
                    rightSibling.Entries.RemoveAt(0);

                    if (!rightSibling.IsLeaf)
                    {
                        childBtreeNode.Children.Add(rightSibling.Children.First());
                        rightSibling.Children.RemoveAt(0);
                    }
                }
                else
                {
                    // this block merges either left or right sibling into the current BtreeNode "child"
                    if (leftSibling != null)
                    {
                        childBtreeNode.Entries.Insert(0, parentBtreeNode.Entries[subtreeIndexInBtreeNode]);
                        var oldEntries = childBtreeNode.Entries;
                        childBtreeNode.Entries = leftSibling.Entries;
                        childBtreeNode.Entries.AddRange(oldEntries);
                        if (!leftSibling.IsLeaf)
                        {
                            var oldChildren = childBtreeNode.Children;
                            childBtreeNode.Children = leftSibling.Children;
                            childBtreeNode.Children.AddRange(oldChildren);
                        }

                        parentBtreeNode.Children.RemoveAt(leftIndex);
                        parentBtreeNode.Entries.RemoveAt(subtreeIndexInBtreeNode);
                    }
                    else
                    {
                        Debug.Assert(rightSibling != null, "BtreeNode should have at least one sibling");
                        childBtreeNode.Entries.Add(parentBtreeNode.Entries[subtreeIndexInBtreeNode]);
                        childBtreeNode.Entries.AddRange(rightSibling.Entries);
                        if (!rightSibling.IsLeaf)
                        {
                            childBtreeNode.Children.AddRange(rightSibling.Children);
                        }

                        parentBtreeNode.Children.RemoveAt(rightIndex);
                        parentBtreeNode.Entries.RemoveAt(subtreeIndexInBtreeNode);
                    }
                }
            }

            // at this point, we know that "child" has at least "degree" BtreeNodes, so we can
            // move on - this guarantees that if any BtreeNode needs to be removed from it to
            // guarantee BTree's property, we will be fine with that
            this.DeleteInternal(childBtreeNode, keyToDelete);
        }