2-3 Trees (Search, Insertion, and Deletion)
2-3 trees are the data structure same as trees, but it has some different properties like any node can have either single value or double value. So, there are two types of nodes in 2-3 trees:
If a node is single-valued then it has two children. Left children will contain values less than parent value, and right children will contain values greater than parent value.
If a node has two values then it will have three children. Left children will contain values lesser than the left parent value, and middle children will contain values greater than the left parent value but less than the right parent value. Right children will contain a value greater than the right parent's value. Since, each node has either two children or three children, that's why it is called 2-3 trees. It is a height-balanced tree, and the reason is all the leaf nodes will be at the same level.
Since, it looks like a binary search tree it also has very good time complexity in terms of searching the element. The real-life application of this data structure is into string files in file systems and database systems. In the worst case, a binary search tree can cost O(n) operation if the height of the tree is near equal to the number of elements, but in the case of a 2-3 tree, there will be O(log N) time complexity.
There are three operations in this tree:
Search is the operation where we are given the root node and target value. If the value is available in the tree, it returns true; else, it will return false.
We can use recursion to search for any element in the tree.
If the current node is single-valued and the value is lesser than the node's value, then call the recursive function for the left child. Else, call the recursive function for the right child.
If the current node is double valued, and if the value is lesser than the left value, then call the recursive function for the left child. If the target element is greater than the current node's left value and lesser than the current node's right value, then call the recursive function for middle children. Else, call the recursive for the right child.
As we know, the recursion base case is the most important condition which helps to terminate the recursive calls. If the current node is null, then we will return false, or if the current node's value is equal to the target element, then we will return true.
If we want to insert any element in the tree, then we will find its correct position, and then we will insert it. We can have three cases in the insertion operation:
Suppose the node at which we want to put the element contains a single value. In this case, we will simply insert the element.
In the above example, we simply put the target in its correct position.
If the node at which we want to insert the target element contains the double value and its parent is single-valued, then we will put the element at the node, and the middle value of the node will be shifted to its parent. And the current node will be split into two separate nodes.
In the above example, we have target element 14, and the node where it will be inserted already has two values which are 11 and 12. So in the first step, we will insert the value at its correct position, and now our node has three values which are 11, 12 and 14, which should not be done. So the middle value is 12, and its parent has a single value, which means we can insert one more value into its parent node. So we will insert 12 to the parent node and split the current node into two nodes where one node will have a value of 11, and another node will have a value of 14.
If the node at which we want to insert is a double-valued node and its parent is also a double-valued node. We will shift the middle element to the parent node and split the current node. Now its parent has three values, so it will also shift its middle element to its parent node and split the parent node into two separate nodes.
A value is removed after being replaced by its in-order successor in order to be deleted. Two nodes must be combined together if a node has less than one data value remaining. After removing a value, a node is merged with another if it becomes empty.