Here's how to handle pointers. This is your B + tree before insertion. (some add-ons are used to make it easier to view pointers)
[21 30 50] / \ \ \ [10|20|-] => [21|22|25] => [30|40|-] => [50|60|80]
After inserting 23 you will have 2 nodes. It is important to know that the left split must always be the same instance , and the right split must be the new node. this will simplify the processing of processing pointers.
Thus, the partition should look like this.
old fresh [21|22|-] => [23|25|-]
since the left node is the same instance, key 21 at the root has the correct right pointer. This is how the nodes look before splitting the root and after splitting the leaf. we are in the middle of the process.
[21 30 50] / \ \ \ [10|20|-] => [21|22|-] => [23|25|-] => [30|40|-] => [50|60|80]
only a new item with key 23 should be added next to 21 in the root directory. since root has no space, it will also be broken. the middle key is 23 (the first element of the right split).
[21 30] [ 50 ] / \ \ * \ [10|20|-] => [21|22|-] => [23|25|-] => [30|40|-] => [50|60|80]
Since root is split, we need to add our middle key left or right and find a new middle key for promotion. pay attention to the null pointer in the right section. because this node is new, it should be initialized soon!
(the root was split to the right of the fact that in the node element fewer elements are in the case of an odd number of elements, but in general it does not matter how you split up.)
our middle key was 23. so add 23.
[21 23 30] [ 50 ] / \ \ \ * \ [10|20|-] => [21|22|-] => [23|25|-] => [30|40|-] => [50|60|80]
Good! If there were no separation here, our insertion would be completed by now. but since there is separation at this level, we must find a new middle key to advance. also don't forget the null pointer for fresh node.
(In the case of leaf splitting, you must keep the key values โโin the sheets and promote a copy of the middle key, but in the case of splitting the internal nodes, you can safely move and push the keys up.)
here the new middle key is 30 . allows you to put it on the left node.
30 \ [30|40|-]
(Itโs important how to choose the middle key. Always the node that receives the middle key from the lower sections should omit one element for the new middle key , if this node is left by the node, discard the last element from it, otherwise release the first element.)
[21 23] 30 [ 50 ] / \ \ \ * \ [10|20|-] => [21|22|-] => [23|25|-] => [30|40|-] => [50|60|80]
Please note that 30 is not in any of the sections. that our middle key we have to process. Always give the right node the middle key to the left of the new node.
[21 23] 30 [50] / \ \ * / \ [10|20|-] => [21|22|-] => [23|25|-] => [30|40|-] => [50|60|80]
Then the right middle key pointer will point to the fresh node on the right split. finally, the middle key moves forward, a new root is created with the left partition to the left and to the right of the right bifurcation and the middle key.
[ 30 ] / \ [21 23] [50] / \ \ / \ [10|20|-] => [21|22|-] => [23|25|-] => [30|40|-] => [50|60|80]
Congrats! you made your insert. it may look easy on paper, but I have to admit it is a bit of a challenge when coding.
There are several ways to represent these key-node elements in memory. my approach is that every key-node element has a right pointer with a key. therefore, each internal node will have an array of key-node s. thus, node keys and pointers are always stored together. the left most children are handled by a separate left pointer, this pointer is stored on each internal node and is never null (after full operations).