|
|
|
|
|
Note:
|
|
|
Comments:
|
|
Comment:
|
|
|
|
|
|
|
|
|
These insertion are of the simple type:
|
|
|
|
Cascading splits/insertions:
|
|
|
|
Because the parent node is the root node, the split operation will create a new root node:
|
Entry put(Key k, Value v)
{
/* -------------------------
Special case: empty tree
------------------------- */
if ( root == null )
{
root = create new root node;
root.entry[0] = (k,v);
return(null);
}
/* -----------------------------------
Find key k in the tree....
----------------------------------- */
p = keySearch(k); // keySearch: see click here
/* -----------------------------------
Handle the case when key k is found
----------------------------------- */
if ( p != null && p.key == k )
{
p.value = v;
return (old Value in p); // Done...
}
/* ------------------------------------------------
Key k not found...
Then: keySearch(k) ended at a node p with
only external children node
------------------------------------------------ */
p = Node of (2,4)-tree where keySearch(k) ended;
// This is a node with only external children node
e = new Entry(k, v); // Create entry using k and v
/* ------------------------------------------------
Invoke a recursive insert procedure
(It MUST be recursive because we may need to
REPEAT the procedure further up the tree !!!
(That is when a node overflows and splits !!!)
------------------------------------------------ */
insertEntryInThisNode(e, null (the right subtree), p);
// Parameters:
// e = the new entry that is inserted
// second parameter = the RIGHT subtree of e
// p = node used to insert e
}
|
Java code:
/* ================================================
put(k): insert (k,v)
================================================ */
Integer put(String k, Integer v)
{
Node p;
Entry e;
/* ------------------------
Special case: empty tree
------------------------ */
if ( root == null )
{
p = new Node();
p.e[0] = new Entry(k, v);
root = p;
p.parent = p; // Parent(root) == root
return(null);
}
/* ------------------------
Other cases
------------------------ */
e = keySearch(k);
// keySearch sets "searchEndPos = last node visited
/* ------------------------
key found, update value
------------------------ */
if ( e != null && k.compareTo(e.key) == 0 )
{
Integer oldValue;
System.out.print("*** Update value of " + k
+ " in entry " + e);
oldValue = e.value;
e.value = v;
return(oldValue);
}
/* ------------------------------------------
key not found:
insert (k,v) in node "searchEndPos"
------------------------------------------ */
e = new Entry(k,v);
insertEntryInThisNode(e, null, searchEndPos);
return(null);
}
|
(Pseudo code):
/* -----------------------------------------------------------
insertEntryInThisNode( e, rightSubTree, p ):
inserts: [e, e's rightSubTree] into node p
Note:
Since p contains multiple entries, we must insert e
in the correct position inside p !!!
This will require moving some elements in an array !!
------------------------------------------------------------ */
void insertEntryInThisNode(Entry e, Node rightSubTree, Node p)
{
/* ----------------------------------------------
Case 1: node p has space left for new entry
---------------------------------------------- */
if ( # enties in p <= 2 )
{
insert [e, rightSubTree] in the correct position inside p
return;
}
/* -------------------------------------------------------------
Case 2: node p is full - split node, and recurse up the tree
Situation:
p's parent
/
/
p: [ p1 k1 p2 k2 p3 k3 p4 ] is full
^
|
k is inserted into p
Note: node p is already PART of the 2,4-tree and will remain
under the SAME parent
A NEW node q will be created that will contain the
RIGHT half of the overflow entries.
The NEW node q has the SAME parent node as p
------------------------------------------------------------- */
q = new Node(); // Make a new node to hold entries
// stored in the RIGHT half of the split
Sort the 3 entries and 4 links in node p
p: (full)
--------------------
p1 k1 p2 k2 p3 k3 p4
and the inserted entry k and its rightSubTree link as follows:
if ( k < k1 )
{
Split into: p1 k rightSubTree k1 p2 k2 p3 k3 p4
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^
p contains: p1 k rightSubTree k1 p2
q contains: p3 k3 p4
n = k2 (Note: q is n's right tree)
}
else if ( k < k2 )
{
Split into: p1 k1 p2 k rightSubTree k2 p3 k3 p4
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^
p contains: p1 k1 p2 k rightSubTree
q contains: p3 k3 p4
n = k2 (Note: q is n's right tree)
}
else if ( k < k3 )
{
Split into: p1 k1 p2 k2 p3 k rightSubTree k3 p4
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
p contains: p1 k1 p2 k2 p3
q contains: rightSubTree k3 p4
n = k (Note: q is n's right tree)
}
else
{
Split into: p1 k1 p2 k2 p3 k3 p4 k rightSubTree
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
p contains: p1 k1 p2 k2 p3
q contains: p4 k rightSubTree
n = k3 (Note: q is n's right tree)
}
# Before:
# p's parent
# /
# /
# p: [ p1 k1 p2 k2 p3 k3 p4 ] is full
# ^
# |
# k is inserted into p
#
# Now:
#
# p's parent
# / q is n's RIGHT child !!!
# /
# p: [ p1 k1' p2 k2' p3 ] q: [ p3 k3' k4 ]
#
# To complete the insert operation: insert [ n q (= n's RIGHT tree)] in p's parent !
# I.e., we must make this tree:
#
#
# [ .. p .. n q ...]
# / \
# / \
# p: [ p1 k1' p2 k2' p3 ] q: [ p3 k3' k4 ]
/* ----------------------------------------------
Handle p = root DIFFERENTLY!!!
---------------------------------------------- */
if ( p == root )
{
/* ---------------------------------------------------------------
Special case: SPLIT the root node (tree wil grow in height !!!
--------------------------------------------------------------- */
newRoot = new Node();
newRoot = p n q; // p = left subtree, n = key, q = right subtree
p.parent = newRoot;
q.parent = newRoot;
root = newRoot; // New root node
}
else
{
/* -------------------------------------------------
Make this link:
p.parent: [ .. p .. n q ...]
| ^
/ \
/ \
p: [ p1 k1' p2 k2' p3 ] q: [ p3 k3' k4 ]
-------------------------------------------------- */
q.parent = p.parent; // q is p's parent's child...
/* -----------------------------------------------------
Insert [n q] in p.parent, i.e., make this happen:
p.parent: [ .. p .. n q ... ]
/ \
/ \
p: [ p1 k1' p2 k2' p3 ] q: [ p3 k3' k4 ]
------------------------------------------------------- */
insertEntryInThisNode(n, q, p.parent);
}
}
|
/* =======================================================
insertEntryInThisNode(e, rightSubTree, p):
1. insert "e" and its "rightSubTree" in node p
2. if over flow, split and insert in parent
======================================================= */
public void insertEntryInThisNode(Entry e, Node rightSubTree, Node p)
{
int i;
Node q;
Entry n;
if ( p.e[2] == null )
{
/* -----------------
There is space
----------------- */
insertEntryDirectlyInNode(e, rightSubTree, p);
// Find the spot for (e, rightSubTree) inside p
// We may need to move array elements !!!
}
else
{
/* -----------------------------------------------
There is no more space .... Split insert !!!
----------------------------------------------- */
/* =======================================
Make a virtual node with 4 keys
(It's easier to sort in an array !!!)
======================================= */
Entry[] x_e = new Entry[4];
Node[] x_child = new Node[5];
x_child[0] = p.child[0];
/* ==================================
1. Fill with keys < k
================================== */
i = 0;
while ( i < 3 && p.e[i].key.compareTo(e.key) < 0 )
{
x_e[i] = p.e[i];
x_child[i+1] = p.child[i+1];
i++;
}
/* =================================================
2. Then fill it with e and it's RIGHT subtree
================================================== */
x_e[i] = e;
x_child[i+1] = rightSubTree;
/* ========================================================
3. Finally, fill it with the rest (these keys are > k)
======================================================== */
while ( i < 3 )
{
x_e[i+1] = p.e[i];
x_child[i+2] = p.child[i+1];
i++;
}
/* =====================================
Distribute keys into p and q
p: first 2 keys
q: last key
===================================== */
p.child[0] = x_child[0];
p.e[0] = x_e[0]; // first key
p.child[1] = x_child[1];
p.e[1] = x_e[1]; // second key
p.child[2] = x_child[2];
p.e[2] = null;
p.child[3] = null;
n = x_e[2]; // n = 3rd key
q = new Node(); // Make a new node to hold the RIGHT half
/* =============================================
Move entries and substrees into NEW node q
============================================= */
q.child[0] = x_child[3];
q.e[0] = x_e[3]; // Last key
q.child[1] = x_child[4];
/* =============================================
Change the PARENT links of these subtrees !!!
============================================= */
if ( q.child[0] != null ) // I forgot these 2 if-statements and
q.child[0].parent = q; // has a hard time finding this bug...
if ( q.child[1] != null )
q.child[1].parent = q;
/* ----------------------------------------------
Handle p = root DIFFERENTLY!!!
---------------------------------------------- */
if ( p == root )
{
/* Split root */
Node newRoot = new Node();
newRoot.child[0] = p;
newRoot.e[0] = n;
newRoot.child[1] = q;
p.parent = newRoot;
q.parent = newRoot;
root = newRoot;
}
else
{
// ************************* Recurse !
q.parent = p.parent;
insertEntryInThisNode(n, q, p.parent);
}
}
}
|
How to run the program:
|
Sample output:
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Enter a key: a Enter a value: 1 put(a,1): == After put(a,1): 0:(a,(-),(-)) vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv cheung@home6(377)> java TestProg vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Enter a key: a Enter a value: 1 put(a,1): == After put(a,1): 0:((a,1),(-),(-)) vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Enter a key: b Enter a value: 2 put(b,2): Insert b in node ((a,1),(-),(-)) == After put(b,2): 0:((a,1),(b,2),(-)) vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Enter a key: b Enter a value: 4 put(b,4): *** Update value of b in entry (b,2) == After put(b,4): 0:((a,1),(b,4),(-)) vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Enter a key: c Enter a value: 7 put(c,7): Insert c in node ((a,1),(b,4),(-)) == After put(c,7): 0:((a,1),(b,4),(c,7)) vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Enter a key: d 4 Enter a value: put(d,4): *** Split insert ! ---- Transitional node = a b (c) d == After put(d,4): 1:((d,4),(-),(-)) 0:((c,7),(-),(-)) 0:((a,1),(b,4),(-)) |