Algorithm


In a B-tree, deletion is a complex operation that involves several steps to maintain the properties of the B-tree. B-trees are self-balancing search trees, commonly used in databases and file systems, where each node can have multiple keys and child pointers. The steps for deletion in a B-tree generally include:

  1. Search for the Key: Start at the root and traverse the tree to find the node containing the key to be deleted. If the key is not present in the tree, the deletion operation stops.

  2. Delete the Key: Once the key is found in a node, delete it. If the node is an internal node, the key can be simply removed. If the node is a leaf, remove the key and handle the deletion according to the type of node.

  3. Handle Underflow: Deleting a key from a node may cause underflow (a violation of the minimum number of keys constraint) in that node. If underflow occurs, borrow a key from a neighboring sibling or merge with a sibling.

  4. Recursively Delete in the Parent: After deleting a key and handling underflow, if the parent node becomes underflowed, repeat the process by deleting the key in the parent node and handling underflow there as well. This recursive process continues until the root is reached.

  5. Update Parent Keys: As you go up the tree, update the keys in the parent nodes to reflect changes in the child nodes.

  6. Adjust Root: If the root becomes underflowed during the deletion process, adjust the root to be the only remaining child.

The specific details of how underflow is handled (borrowing or merging with siblings) and the exact rules for updating keys depend on the variant of B-tree (e.g., B-tree, B+ tree) and the specific implementation.

 

Code Examples

#1 Deletion from a B-tree implement in Python

Code - Python Programming

class BTreeNode:
    def __init__(self, leaf=True):
        self.keys = []
        self.children = []
        self.leaf = leaf

class BTree:
    def __init__(self, t):
        self.root = BTreeNode()
        self.t = t

    def insert(self, key):
        root = self.root
        if len(root.keys) == (2 * self.t) - 1:
            new_root = BTreeNode()
            new_root.children.append(self.root)
            self.split(new_root, 0)
            self.root = new_root
        self._insert(self.root, key)

    def _insert(self, node, key):
        index = len(node.keys) - 1
        if node.leaf:
            node.keys.append(0)  # Make space for the new key
            while index >= 0 and key < node.keys[index]:
                node.keys[index + 1] = node.keys[index]
                index -= 1
            node.keys[index + 1] = key
        else:
            while index >= 0 and key < node.keys[index]:
                index -= 1
            index += 1
            if len(node.children[index].keys) == (2 * self.t) - 1:
                self.split(node, index)
                if key > node.keys[index]:
                    index += 1
            self._insert(node.children[index], key)

    def split(self, parent, index):
        t = self.t
        child = parent.children[index]
        new_child = BTreeNode(leaf=child.leaf)
        parent.keys.insert(index, child.keys[t - 1])
        parent.children.insert(index + 1, new_child)
        new_child.keys = child.keys[t:2 * t - 1]
        child.keys = child.keys[:t - 1]
        if not child.leaf:
            new_child.children = child.children[t:]
            child.children = child.children[:t]

    def delete(self, key):
        self._delete(self.root, key)

    def _delete(self, node, key):
        index = 0
        while index < len(node.keys) and key > node.keys[index]:
            index += 1

        if node.leaf:
            if key in node.keys:
                node.keys.remove(key)
            else:
                print(f"Key {key} not found.")
        else:
            child = node.children[index]
            if len(child.keys) >= self.t:
                self._delete(child, key)
            elif index > 0 and len(node.children[index - 1].keys) >= self.t:
                self.borrowFromPrev(node, index)
            elif index < len(node.children) - 1 and len(node.children[index + 1].keys) >= self.t:
                self.borrowFromNext(node, index)
            elif index > 0:
                self.merge(node, index - 1)
                self._delete(node.children[index - 1], key)
            else:
                self.merge(node, index)
                self._delete(node.children[index], key)

    def borrowFromPrev(self, node, index):
        child = node.children[index]
        sibling = node.children[index - 1]
        child.keys.insert(0, node.keys[index - 1])
        node.keys[index - 1] = sibling.keys.pop()

        if not child.leaf:
            child.children.insert(0, sibling.children.pop())

    def borrowFromNext(self, node, index):
        child = node.children[index]
        sibling = node.children[index + 1]
        child.keys.append(node.keys[index])
        node.keys[index] = sibling.keys.pop(0)

        if not child.leaf:
            child.children.append(sibling.children.pop(0))

    def merge(self, node, index):
        child = node.children[index]
        sibling = node.children[index + 1]
        child.keys.append(node.keys.pop(index))
        child.keys.extend(sibling.keys)

        if not child.leaf:
            child.children.extend(sibling.children)

        node.children.pop(index + 1)

# Example usage:
b_tree = BTree(t=3)
keys_to_insert = [3, 7, 1, 8, 5, 12, 9, 6, 11, 2, 4, 10]
for key in keys_to_insert:
    b_tree.insert(key)

print("B-tree after insertion:")
# Display the tree structure (you may want to customize this based on your needs)
print("Root:", b_tree.root.keys)
for i, child in enumerate(b_tree.root.children):
    print(f"Child {i}:", child.keys)

key_to_delete = 6
b_tree.delete(key_to_delete)
print(f"\nB-tree after deleting key {key_to_delete}:")
print("Root:", b_tree.root.keys)
for i, child in enumerate(b_tree.root.children):
    print(f"Child {i}:", child.keys)
Copy The Code & Try With Live Editor

#2 Deletion from a B-tree implement in Java

Code - Java Programming

To implement deletion in a B-tree in Java, you need to follow a series of steps to maintain the properties of the B-tree while removing a key. Here's a basic outline of how you might approach this task:

    Search for the Key:
        Start at the root and traverse the tree to find the node containing the key to be deleted.
        If the key is not present, the deletion operation is complete.

    Delete Key from Node:
        If the key is in a leaf node, simply remove it.
        If the key is in an internal node, you need to handle this case differently. You can replace the key with its predecessor or successor from the left or right subtree.

    Handle Underflow:
        After deletion, check if the node underflows (i.e., has fewer keys than the minimum required).
        If underflow occurs, borrow a key from a neighboring node, redistribute keys, or merge nodes to maintain the B-tree properties.

    Recursively Delete in Child Nodes:
        If you have merged or borrowed keys, and the parent node is underflowed, apply the same steps recursively.

    Update Root:
        If the root node becomes empty after deletion, update the root to be its only child.
Copy The Code & Try With Live Editor

#3 Deletion from a B-tree implement in C

Code - C Programming

Assuming you have a B-tree node structure defined as follows:

// B-tree node structure
typedef struct BTreeNode {
    int *keys;   // Array to store keys
    struct BTreeNode **children;  // Array to store child pointers
    int n;       // Current number of keys
    int leaf;    // 1 if node is a leaf, 0 otherwise
} BTreeNode;
 < /code>

And a B-tree structure:

// B-tree structure
typedef struct BTree {
    BTreeNode *root;
    int t;  // Minimum degree
} BTree;
 < /code>

Here is a high-level C implementation of the B-tree deletion operation:

#include <stdio.h>
#include <stdlib.h>

// Assume other B-tree functions (e.g., search, insert) are implemented

// Function to delete a key from the B-tree
void deleteKey(BTreeNode *root, int key) {
    if (!root) {
        printf("The tree is empty.\n");
        return;
    }

    // Perform deletion
    // Implementation details will depend on the specific B-tree deletion algorithm

    // Example: Call a delete function based on the B-tree type (e.g., B-tree, B+ tree)
    deleteKeyInBTree(root, key);
}

// Function to delete a key from a B-tree node
void deleteKeyInBTree(BTreeNode *node, int key) {
    // Implementation details will depend on the specific B-tree deletion algorithm

    // Example: Handle deletion based on whether the node is a leaf or not
    if (node->leaf) {
        // Handle deletion in a leaf node
        deleteKeyInLeaf(node, key);
    } else {
        // Handle deletion in an internal node
        deleteKeyInInternalNode(node, key);
    }
}

// Function to delete a key from a leaf node
void deleteKeyInLeaf(BTreeNode *node, int key) {
    // Implementation details will depend on the specific B-tree deletion algorithm
    // Example: Implement deletion in a leaf node
}

// Function to delete a key from an internal node
void deleteKeyInInternalNode(BTreeNode *node, int key) {
    // Implementation details will depend on the specific B-tree deletion algorithm
    // Example: Implement deletion in an internal node
}

int main() {
    // Example usage
    BTree *tree = createBTree(3);  // Assume B-tree with minimum degree 3

    // Insert keys into the B-tree
    insertKey(tree, 10);
    insertKey(tree, 20);
    insertKey(tree, 5);
    insertKey(tree, 6);
    insertKey(tree, 12);
    insertKey(tree, 30);
    insertKey(tree, 7);
    insertKey(tree, 17);

    // Print the B-tree
    printf("B-tree before deletion:\n");
    printBTree(tree->root);

    // Delete a key from the B-tree
    int keyToDelete = 6;
    deleteKey(tree->root, keyToDelete);

    // Print the B-tree after deletion
    printf("\nB-tree after deletion of key %d:\n", keyToDelete);
    printBTree(tree->root);

    return 0;
}
Copy The Code & Try With Live Editor

#4 Deletion from a B-tree implement in C++

Code - C++ Programming

#include <iostream>

const int MIN_KEYS = 1; // Minimum number of keys for a node

struct Node {
    int *keys;
    Node **children;
    bool isLeaf;
    int numKeys;
};

class BTree {
private:
    Node *root;

    // Helper function to search for a key in a node
    int findKeyIndex(Node *node, int key) {
        int index = 0;
        while (index  <  node->numKeys && key > node->keys[index]) {
            ++index;
        }
        return index;
    }

    // Helper function to borrow a key from the predecessor
    void borrowFromPrev(Node *node, int index) {
        Node *child = node->children[index];
        Node *sibling = node->children[index - 1];

        for (int i = child->numKeys - 1; i >= 0; --i) {
            child->keys[i + 1] = child->keys[i];
        }

        if (!child->isLeaf) {
            for (int i = child->numKeys; i >= 0; --i) {
                child->children[i + 1] = child->children[i];
            }
        }

        child->keys[0] = node->keys[index - 1];

        if (!child->isLeaf) {
            child->children[0] = sibling->children[sibling->numKeys];
        }

        node->keys[index - 1] = sibling->keys[sibling->numKeys - 1];

        child->numKeys += 1;
        sibling->numKeys -= 1;
    }

    // Helper function to borrow a key from the successor
    void borrowFromNext(Node *node, int index) {
        Node *child = node->children[index];
        Node *sibling = node->children[index + 1];

        child->keys[child->numKeys] = node->keys[index];

        if (!child->isLeaf) {
            child->children[child->numKeys + 1] = sibling->children[0];
        }

        node->keys[index] = sibling->keys[0];

        for (int i = 1; i  <  sibling->numKeys; ++i) {
            sibling->keys[i - 1] = sibling->keys[i];
        }

        if (!sibling->isLeaf) {
            for (int i = 1; i  < = sibling->numKeys; ++i) {
                sibling->children[i - 1] = sibling->children[i];
            }
        }

        child->numKeys += 1;
        sibling->numKeys -= 1;
    }

    // Helper function to merge a child with its sibling
    void merge(Node *node, int index) {
        Node *child = node->children[index];
        Node *sibling = node->children[index + 1];

        child->keys[MIN_KEYS - 1] = node->keys[index];

        for (int i = 0; i  <  sibling->numKeys; ++i) {
            child->keys[i + MIN_KEYS] = sibling->keys[i];
        }

        if (!child->isLeaf) {
            for (int i = 0; i  < = sibling->numKeys; ++i) {
                child->children[i + MIN_KEYS] = sibling->children[i];
            }
        }

        for (int i = index + 1; i  <  node->numKeys; ++i) {
            node->keys[i - 1] = node->keys[i];
        }

        for (int i = index + 2; i  < = node->numKeys; ++i) {
            node->children[i - 1] = node->children[i];
        }

        child->numKeys += sibling->numKeys + 1;
        node->numKeys -= 1;

        delete sibling;
    }

    // Helper function to delete a key from a node
    void removeFromNode(Node *node, int index) {
        if (node->isLeaf) {
            for (int i = index + 1; i  <  node->numKeys; ++i) {
                node->keys[i - 1] = node->keys[i];
            }
            node->numKeys -= 1;
        } else {
            Node *child = node->children[index];
            Node *successor = node->children[index + 1];

            if (child->numKeys >= MIN_KEYS) {
                int predecessorKey = getPredecessor(child);
                removeFromNode(child, findKeyIndex(child, predecessorKey));
                node->keys[index] = predecessorKey;
            } else if (successor->numKeys >= MIN_KEYS) {
                int successorKey = getSuccessor(successor);
                removeFromNode(successor, findKeyIndex(successor, successorKey));
                node->keys[index] = successorKey;
            } else {
                merge(node, index);
                removeFromNode(child, MIN_KEYS - 1);
            }
        }
    }

    // Helper function to get the predecessor key
    int getPredecessor(Node *node) {
        while (!node->isLeaf) {
            node = node->children[node->numKeys];
        }
        return node->keys[node->numKeys - 1];
    }

    // Helper function to get the successor key
    int getSuccessor(Node *node) {
        while (!node->isLeaf) {
            node = node->children[0];
        }
        return node->keys[0];
    }

    // Helper function to delete a key from the B-tree
    void deleteKey(Node *node, int key) {
        int index = findKeyIndex(node, key);

        if (index  <  node->numKeys && node->keys[index] == key) {
            removeFromNode(node, index);
        } else {
            if (node->isLeaf) {
                std::cout << "Key " << key << " not found in the tree.\n";
                return;
            }

            bool isLastChild = (index == node->numKeys);

            if (node->children[index]->numKeys  <  MIN_KEYS) {
                fill(node, index);
            }

            if (isLastChild && index > node->numKeys) {
                deleteKey(node->children[index - 1], key);
            } else {
                deleteKey(node->children[index], key);
            }
        }
    }

    // Helper function to fill a child that has less than MIN_KEYS keys
    void fill(Node *node, int index) {
        if (index != 0 && node->children[index - 1]->numKeys >= MIN_KEYS) {
            borrowFromPrev(node, index);
        } else if (index != node->numKeys && node->children[index + 1]->numKeys >= MIN_KEYS) {
            borrowFromNext(node, index);
        } else {
            if (index != node->numKeys) {
                merge(node, index);
            } else {
                merge(node, index - 1);
            }
        }
    }

public:
    BTree() : root(nullptr) {}

    // Function to delete a key from the B-tree
    void deleteKey(int key) {
Copy The Code & Try With Live Editor
Advertisements

Demonstration


Deletion from a B-tree-DevsEnv