2-3-4 Trees A 2-3-4 Tree is one in which each node may have 2, 3, or 4 children. For non-leaf nodes, we can have 3 possible arrangements: 1. a node with 1 data item always has 2 children 2. a node with 2 data items always has 3 children 3. a node with 3 data items always has 4 children Additional rules: 1. a leaf node has no children 2. empty nodes (0 data items) are not permitted Some terminology: In general, a 2-3-4 tree looks like this: DataItem0 DataItem1 DataItem2 / | | \ Child0 Child1 Child2 Child3 Data is organized much the same as in a binary tree- smaller values to the left of the key and larger values to the right. However, this becomes more complicated when there is more than one value in the node. The additional rule for handling this is: A value in a child node must fall between the adjacent values of the parent node. Example: A 3-node -------- 40 62 xx / | \ / | \ / | \ / | \ -------- -------- -------- 27 33 xx 51 55 59 83 xx xx Note: xx means there is no value in that part of the node. A node has the potential of containing up to three values. Searching: A search works similar to that of a binary tree. If the value to be found is not in the current node, then choose the appropriate child node to move to for continuing the search. bool search(int searchValue, node curNode) { bool bRetVal = false; if ( curNode != NULL ) bRetVal = true; else if ( findItem(searchValue, curNode) ) bRetVal = true; else if ( !isLeaf(curNode) ) bRetVal = search(searchValue, nextChild(searchValue, curNode)); return bRetVal; } bool findItem(int searchValue, node curNode) { if ( curNode.DataItem0 == searchValue ) return true; if ( curNode.DataItem1 == searchValue ) return true; if ( curNode.DataItem2 == searchValue ) return true; } bool isLeaf(node curNode) { if ( curNode.Child0 != NULL ) return false; if ( curNode.Child1 != NULL ) return false; if ( curNode.Child2 != NULL ) return false; if ( curNode.Child3 != NULL ) return false; } node nextChild(int searchValue, node curNode) { if ( searchValue < curNode.DataItem0 ) return curNode.Child0; if ( searchValue < curNode.DataItem1 ) return curNode.Child1; if ( searchValue < curNode.DataItem2 ) return curNode.Child2; return curNode.Child3; } Inserting New values are always inserted into a leaf. A top-down approach is often taken. The process is as follows: 1. Start the search at the root node. 2. As you search, split any node that is full. 3. Place the value in the appropriate position within the node. Splitting a Node 1. Create a new node. It will be a sibling of the node being split, and is placed to the right. 2. Move the value in DataItem2 into the new node. 3. Move the value in DataItem1 into the parent node. 4. Keep the value in DataItem0 remains where it is. 5. Disconnect the right-most two children of the node being split, and connect them to the new node. Splitting the Root One extra step needs to be taken when the root node is full, because there is no parent for Step 3 above. Before doing the steps above, create a new node. This node becomes the parent of the node being split. Example: Inserting 79 1. -------- -------- 69 72 84 xx xx xx / | | \ / / \ \ / | | \ / / \ \ / | | \ -------- -------- -------- -------- 74 xx xx 67 69 xx 77 xx xx 92 xx xx 2. -------- -------- 69 72 xx 84 xx xx / | | \ / / \ \ / | | \ / / \ \ / | | \ -------- -------- -------- -------- 74 xx xx 67 69 xx 77 xx xx 92 xx xx 3. -------- -------- 69 xx xx 84 xx xx / | | \ / / \ \ / | | \ / / \ \ / | | \ -------- -------- -------- -------- 74 xx xx 67 69 xx 77 xx xx 92 xx xx 5. -------- -------- 69 xx xx 84 xx xx / | | \ / / \ \ / | | \ / / \ \ / | | \ -------- -------- -------- -------- 74 xx xx 67 69 xx 77 xx xx 92 xx xx -------- -------- 69 xx xx 84 xx xx / | | \ / / \ \ / | | \ / / \ \ / | | \ -------- -------- -------- -------- 74 xx xx 67 69 xx 77 79 xx 92 xx xx bool insertValue(int value) { node n = root; int t = 0; while ( !isLeaf(n) ) { if ( isFull(n) ) splitNode(n); n = nextChild(value, n); } placeValue(value, n); } void splitNode(node n) { node newNode = new node; if ( n == root ) { node r = new node; r.Child0 = n; r.Child1 = newNode; } else { setLink(n.Parent, newNode); } newNode.DataItem0 = n.DataItem2; placeValue(n.DataItem1, n.Parent); newNode.Child0 = n.Child2; newNode.Child1 = n.Child3; n.Child2 = NULL; n.Child3 = NULL; } bool isFull(node curNode) { if ( curNode.DataItem0 == 0 ) return false; if ( curNode.DataItem1== 0 ) return false; if ( curNode.DataItem2== 0 ) return false; } void placeValue(int v, node n) { int temp = 0; if ( n.DataItem0 == 0 ) { n.DataItem0 = v; return; } else if ( v < n.DataItem0 ) { temp = v; v = n.DataItem0; n.DataItem0 = temp; } if ( n.DataItem1 == 0 ) { n.DataItem1 = v; return; } else if ( v < n.DataItem1 ) { temp = v; v = n.DataItem1; n.DataItem1 = temp; } if ( n.DataItem2 == 0 ) { n.DataItem2 = v; return; } else if ( v < n.DataItem2 ) { temp = v; v = n.DataItem2; n.DataItem2 = temp; } } void setLink(node n1, node n2) { if ( n1.Child0 == NULL ) { n1.Child0 = n2; return; } if ( n1.Child1 == NULL ) { n1.Child1 = n2; return; } if ( n1.Child2 == NULL ) { n1.Child2 = n2; return; } if ( n1.Child3 == NULL ) { n1.Child3 = n2; return; } }