2-3 Trees
#include <iostream>
#include <queue>
using namespace std;
struct Node {
int key1, key2;
Node *left, *middle, *right;
Node(int key) {
key1 = key;
key2 = -1;
left = middle = right = nullptr;
}
Node(int key1, int key2, Node* left, Node* middle, Node* right) {
this->key1 = key1;
this->key2 = key2;
this->left = left;
this->middle = middle;
this->right = right;
}
};
class TwoThreeTree {
public:
Node* root;
TwoThreeTree() { root = nullptr; }
void insert(int key);
Node* insert(Node* node, int key);
void split(Node*& node);
Node* deleteKey(Node* node, int key);
void inorder(Node* node);
bool search(Node* node, int key);
void remove(int key);
void display(Node* node);
};
void TwoThreeTree::insert(int key) {
root = insert(root, key);
}
Node* TwoThreeTree::insert(Node* node, int key) {
if (!node) return new Node(key);
if (node->key2 == -1) {
if (key < node->key1) {
if (!node->left) node->left = new Node(key);
else node->left = insert(node->left, key);
} else {
if (!node->right) node->right = new Node(key);
else node->right = insert(node->right, key);
}
} else {
if (key < node->key1) {
node->left = insert(node->left, key);
} else if (key > node->key2) {
node->right = insert(node->right, key);
} else {
node->middle = insert(node->middle, key);
}
}
split(node);
return node;
}
void TwoThreeTree::split(Node*& node) {
if (!node || node->key2 == -1) return;
Node* newRight = new Node(node->key2);
newRight->left = node->middle;
newRight->right = node->right;
node->middle = nullptr;
node->right = nullptr;
node->key2 = -1;
}
Node* TwoThreeTree::deleteKey(Node* node, int key) {
if (!node) return nullptr;
if (key == node->key1 || key == node->key2) {
if (!node->left) {
if (node->key2 == -1 || key == node->key2) {
node->key2 = -1;
} else {
node->key1 = node->key2;
node->key2 = -1;
}
return node;
}
}
if (key < node->key1) node->left = deleteKey(node->left, key);
else if (node->key2 == -1 || key < node->key2) node->middle = deleteKey(node->middle,
key);
else node->right = deleteKey(node->right, key);
return node;
}
void TwoThreeTree::remove(int key) {
root = deleteKey(root, key);
}
void TwoThreeTree::inorder(Node* node) {
if (!node) return;
inorder(node->left);
cout << node->key1 << " ";
inorder(node->middle);
if (node->key2 != -1) {
cout << node->key2 << " ";
inorder(node->right);
}
}
// **Improved BFS Display**
void TwoThreeTree::display(Node* node) {
if (!node) {
cout << "Tree is empty.\n";
return;
}
queue<Node*> q;
q.push(node);
cout << "\nTree Structure (Level Order):\n";
while (!q.empty()) {
int levelSize = q.size(); // Number of nodes in the current level
while (levelSize--) {
Node* current = q.front();
q.pop();
// Print current node keys
if (current) {
if (current->key2 == -1)
cout << "[" << current->key1 << "] ";
else
cout << "[" << current->key1 << ", " << current->key2 << "] ";
// Push children (even if NULL, to maintain tree structure)
q.push(current->left);
q.push(current->middle);
q.push(current->right);
} else {
cout << "[ ] "; // Placeholder for NULL
}
}
cout << endl; // New line after each level
}
}
bool TwoThreeTree::search(Node* node, int key) {
if (!node) return false;
if (key == node->key1 || key == node->key2) return true;
if (key < node->key1) return search(node->left, key);
if (node->key2 == -1 || key < node->key2) return search(node->middle, key);
return search(node->right, key);
}
int main() {
TwoThreeTree tree;
int keys[] = {9, 5, 8, 3, 2, 4, 7}; // Updated keys
for (int key : keys) {
tree.insert(key);
}
// Display full tree once after all insertions
tree.display(tree.root);
cout << "\nInorder Traversal: ";
tree.inorder(tree.root);
cout << endl;
// Search for keys
for (int key : {4, 6}) { // Searching for 4 and a non-existent key 6
cout << "Search " << key << ": ";
if (tree.search(tree.root, key))
cout << "Found\n";
else
cout << "Not Found\n";
}
// Remove a key and display the tree again
cout << "\nRemoving key 4...\n";
tree.remove(4);
tree.display(tree.root);
return 0;
}
/ C++ program for B-Tree insertion
#include<iostream>
using namespace std;
// A BTree node
class BTreeNode
{
int *keys; // An array of keys
int t; // Minimum degree (defines the range for number of keys)
BTreeNode **C; // An array of child pointers
int n; // Current number of keys
bool leaf; // Is true when node is leaf. Otherwise false
public:
BTreeNode(int _t, bool _leaf); // Constructor
// A utility function to insert a new key in the subtree rooted with
// this node. The assumption is, the node must be non-full when this
// function is called
void insertNonFull(int k);
// A utility function to split the child y of this node. i is index of y in
// child array C[]. The Child y must be full when this function is called
void splitChild(int i, BTreeNode *y);
// A function to traverse all nodes in a subtree rooted with this node
void traverse();
// A function to search a key in the subtree rooted with this node.
BTreeNode *search(int k); // returns NULL if k is not present.
// Make BTree friend of this so that we can access private members of this
// class in BTree functions
friend class BTree;
};
// A BTree
class BTree
{
BTreeNode *root; // Pointer to root node
int t; // Minimum degree
public:
// Constructor (Initializes tree as empty)
BTree(int _t)
{ root = NULL; t = _t; }
// function to traverse the tree
void traverse()
{ if (root != NULL) root->traverse(); }
// function to search a key in this tree
BTreeNode* search(int k)
{ return (root == NULL)? NULL : root->search(k); }
// The main function that inserts a new key in this B-Tree
void insert(int k);
};
// Constructor for BTreeNode class
BTreeNode::BTreeNode(int t1, bool leaf1)
{
// Copy the given minimum degree and leaf property
t = t1;
leaf = leaf1;
// Allocate memory for maximum number of possible keys
// and child pointers
keys = new int[2*t-1];
C = new BTreeNode *[2*t];
// Initialize the number of keys as 0
n = 0;
}
// Function to traverse all nodes in a subtree rooted with this node
void BTreeNode::traverse()
{
// There are n keys and n+1 children, traverse through n keys
// and first n children
int i;
for (i = 0; i < n; i++)
{
// If this is not leaf, then before printing key[i],
// traverse the subtree rooted with child C[i].
if (leaf == false)
C[i]->traverse();
cout << " " << keys[i];
}
// Print the subtree rooted with last child
if (leaf == false)
C[i]->traverse();
}
// Function to search key k in subtree rooted with this node
BTreeNode *BTreeNode::search(int k)
{
// Find the first key greater than or equal to k
int i = 0;
while (i < n && k > keys[i])
i++;
// If the found key is equal to k, return this node
if (keys[i] == k)
return this;
// If key is not found here and this is a leaf node
if (leaf == true)
return NULL;
// Go to the appropriate child
return C[i]->search(k);
}
// The main function that inserts a new key in this B-Tree
void BTree::insert(int k)
{
// If tree is empty
if (root == NULL)
{
// Allocate memory for root
root = new BTreeNode(t, true);
root->keys[0] = k; // Insert key
root->n = 1; // Update number of keys in root
}
else // If tree is not empty
{
// If root is full, then tree grows in height
if (root->n == 2*t-1)
{
// Allocate memory for new root
BTreeNode *s = new BTreeNode(t, false);
// Make old root as child of new root
s->C[0] = root;
// Split the old root and move 1 key to the new root
s->splitChild(0, root);
// New root has two children now. Decide which of the
// two children is going to have new key
int i = 0;
if (s->keys[0] < k)
i++;
s->C[i]->insertNonFull(k);
// Change root
root = s;
}
else // If root is not full, call insertNonFull for root
root->insertNonFull(k);
}
}
// A utility function to insert a new key in this node
// The assumption is, the node must be non-full when this
// function is called
void BTreeNode::insertNonFull(int k)
{
// Initialize index as index of rightmost element
int i = n-1;
// If this is a leaf node
if (leaf == true)
{
// The following loop does two things
// a) Finds the location of new key to be inserted
// b) Moves all greater keys to one place ahead
while (i >= 0 && keys[i] > k)
{
keys[i+1] = keys[i];
i--;
}
// Insert the new key at found location
keys[i+1] = k;
n = n+1;
}
else // If this node is not leaf
{
// Find the child which is going to have the new key
while (i >= 0 && keys[i] > k)
i--;
// See if the found child is full
if (C[i+1]->n == 2*t-1)
{
// If the child is full, then split it
splitChild(i+1, C[i+1]);
// After split, the middle key of C[i] goes up and
// C[i] is splitted into two. See which of the two
// is going to have the new key
if (keys[i+1] < k)
i++;
}
C[i+1]->insertNonFull(k);
}
}
// A utility function to split the child y of this node
// Note that y must be full when this function is called
void BTreeNode::splitChild(int i, BTreeNode *y)
{
// Create a new node which is going to store (t-1) keys
// of y
BTreeNode *z = new BTreeNode(y->t, y->leaf);
z->n = t - 1;
// Copy the last (t-1) keys of y to z
for (int j = 0; j < t-1; j++)
z->keys[j] = y->keys[j+t];
// Copy the last t children of y to z
if (y->leaf == false)
{
for (int j = 0; j < t; j++)
z->C[j] = y->C[j+t];
}
// Reduce the number of keys in y
y->n = t - 1;
// Since this node is going to have a new child,
// create space of new child
for (int j = n; j >= i+1; j--)
C[j+1] = C[j];
// Link the new child to this node
C[i+1] = z;
// A key of y will move to this node. Find the location of
// new key and move all greater keys one space ahead
for (int j = n-1; j >= i; j--)
keys[j+1] = keys[j];
// Copy the middle key of y to this node
keys[i] = y->keys[t-1];
// Increment count of keys in this node
n = n + 1;
}
// Driver program to test above functions
int main()
{
BTree t(3); // A B-Tree with minimum degree 3
t.insert(10);
t.insert(20);
t.insert(5);
t.insert(6);
t.insert(12);
t.insert(30);
t.insert(7);
t.insert(17);
cout << "Traversal of the constructed tree is ";
t.traverse();
int k = 6;
(t.search(k) != NULL)? cout << "\nPresent" : cout << "\nNot Present";
k = 15;
(t.search(k) != NULL)? cout << "\nPresent" : cout << "\nNot Present";
return 0;
}