Integer remove(Key k)
{
Entry e;
Node p;
/* -----------------------
Find k to remove
----------------------- */
e = keySearch(k);
/* =======================
Check if k exists...
======================= */
if ( e == null )
{
return(null); // Not found, nothing to delete...
}
/* ========================= We found the entry =============== */
Entry Old = e; // Remember the old value (to return it)
/* ------------------------------
Step 1: remove entry e
------------------------------ */
p = node that contains entry e;
if ( p == a leaf node )
{
Delete entry e from p;
// Note: this requires moving array elements
}
else /* Delete entry from internal node */
{
/* -------------------------------
Replace e with e's successor
------------------------------- */
succ = successor entry of the deleted entry e;
q = node that contains the succ entry;
Replace entry e (in node p) with "succ" entry;
Delete the succ entry from node q;
// Note: this requires moving array elements
p = q;
}
/* ***********************************************
Handle a possible underflow situation
*********************************************** */
if ( p is empty )
{
handleUnderflow(p, null); // This is a recursive routine !
// The second parameter is a subtree that hangs under
// the underflow node (the red reference in my figures)
}
return old.value; // Return
}
|
public Integer remove(String k)
{
Entry e;
Node p;
int pos;
/* -----------------------
Find k to remove
----------------------- */
e = keySearch(k);
/* =======================
Check if k exists...
======================= */
if ( e == null )
{
return(null); // Not found, nothing to delete...
}
/* ========================= We found the entry =============== */
Entry old = e; // Save for return value
/* ----------------------------------------------------
Note:
searchEndPos = node containing entry e
---------------------------------------------------- */
p = searchEndPos;
/* ----------------------------------------------------
Find position of e inside p:
p --> | T0 | e0 | T1 | e1 | T2 | e2 | T3 |
Which of the e? is e ????
---------------------------------------------------- */
for ( pos = 0; pos < 3; pos++ )
if ( p.e[pos] == e )
break;
/* ----------------------------------------------------
Delete entry e from 2,4-tree
---------------------------------------------------- */
if ( p.child[0] == null /* ====> leaf node */ )
{
/* ==================================================
Delete entry e from a leaf node
Note: this is done by MOVING right most entries
into the slot containing e !!!
================================================== */
for ( int i = pos; i < 2; i++ )
p.e[i] = p.e[i+1];
p.e[2] = null; // The right most entry is for sure null !
}
else
{
/* ------------------------------------------------
Non-leaf: 1. replace e with e's successor
------------------------------------------------ */
Node q;
/* ------------------------------------------------
Use q to traverse to p's successor
------------------------------------------------ */
q = p.child[pos+1]; // Go right
while ( q.child[0] != null )
q = q.child[0]; // Go left all the way down.
/* ------------------------------------------------
Replace e by succ
------------------------------------------------ */
p.e[pos] = q.e[0]; // Replace e by e's successor
/* ==============================================
Delete succ from q (succ is always at pos 0)
============================================== */
for ( int i = 0; i < 2; i++ ) // Delete e's successor in q
q.e[i] = q.e[i+1];
q.e[2] = null;
/* -----------------------------------------------------
The target entry is now q
----------------------------------------------------- */
p = q; // node where entry was deleted
}
/* *********************************************************
Check for underflow situation in delete target location
********************************************************* */
if ( p.e[0] == null /* <===> node is empty */ )
{
handleUnderflow(p, null); // Node p is empty
// Second parameter is a subtree
// hung under p
}
return old.value; // Return old value
}
|
/* -------------------------------------------------------
handleUnderflow(p, Z): handle the overflow condition in
node p (p = empty !)
Z = subtree that is left hanging when p became empty
------------------------------------------------------- */
void handleUnderflow(Node p, Node Z)
{
/* ----------------------------
Check if p is the root
---------------------------- */
if ( p == root )
{
root = Z; // The subtree is the new tree !!
return; // DONE !
}
/* ===================================================
Gather information before transfer or merge
=================================================== */
Node parent;
int pos;
parent = p.parent;
pos = index of subtree p in parent; // pos = 0, 1, 2
/* -------------------------------------------------------------
The meaning of pos:
p's parent --> | C0 | e0 | C1 | e1 | C2 | e2 | C3 |
^ ^ ^ ^
| | | |
if: C0==p C1==p C2==p C3==p
then: pos=0 pos=1 pos=2 pos=3
-------------------------------------------------------------- */
/* -------------------------------------------------------------
Try: TRANSFER against your right sibling
------------------------------------------------------------- */
if ( p has a right sibling && p's right sibling has >= 2 entries )
{
/* -------------------------------------
Transfer with right sibling
See: click here
------------------------------------- */
R_Sibling = p's right sibling node;
Perform this transfer:
|
public void handleUnderflow(Node p, Node Z)
{
/* ================================================
Check if the root node is empty
Note: This is a base case of the recursion....
================================================ */
if ( p == root )
{
root = Z; // Delete the empty root node p
return;
}
/* ===================================================
Gather information before transfer or merge
=================================================== */
Node parent;
int pos;
parent = p.parent;
for ( pos = 0; pos < 4; pos++ )
{
if ( parent.child[pos] == p )
break;
}
/* -------------------------------------------------------------
The meaning of pos:
p's parent --> | C0 | e0 | C1 | e1 | C2 | e2 | C3 |
^ ^ ^ ^
| | | |
if: C0==p C1==p C2==p C3==p
then: pos=0 pos=1 pos=2 pos=3
-------------------------------------------------------------- */
/* -------------------------------------------------------------
TRY a TRANSFER with your RIGHT sibling
------------------------------------------------------------- */
if ( (pos <= 2 && parent.child[pos+1] != null) /* p has a right sibling */
&& parent.child[pos+1].e[1] != null /* R sibling has >= 2 entries */)
{
Node R_sibling = parent.child[pos+1];
|
How to run the program:
|
Sample output:
Legend:
red denotes the next deleted entry
darkred denotes the entries involved in op
darkgreen shows when the involved entries end up
2:((m,6),(-),(-))
3:((ka,6),(l,6),(-))
1:((kb,6),(-),(-))
0:((j,6),(k,6),(-))
1:((h,8),(-),(-))
2:((g,7),(-),(-))
0:((e,5),(f,6),(-))
0:((ba,6),(d,4),(i,9))
1:((ca,6),(-),(-))
1:((c,3),(-),(-))
0:((bb,6),(-),(-))
3:((b,2),(-),(-))
2:((ae,6),(af,6),(-)) <--- will be replaced by (ae,6)
0:((ab,6),(ad,6),(ax,6))
1:((ac,6),(-),(-))
0:((a,1),(aa,6),(-))
==================================================================
== After remove(ad):
2:((m,6),(-),(-))
3:((ka,6),(l,6),(-))
1:((kb,6),(-),(-))
0:((j,6),(k,6),(-))
1:((h,8),(-),(-))
2:((g,7),(-),(-))
0:((e,5),(f,6),(-))
0:((ba,6),(d,4),(i,9))
1:((ca,6),(-),(-))
1:((c,3),(-),(-))
0:((bb,6),(-),(-))
3:((b,2),(-),(-))
2:((af,6),(-),(-))
0:((ab,6),(ae,6),(ax,6))
1:((ac,6),(-),(-))
0:((a,1),(aa,6),(-)) <---- will TRANSFER with Left sibling
====================================================
Underflow !!!! ===> Transfer with L sibling ((a,1),(aa,6),(-))
== After remove(ac):
2:((m,6),(-),(-))
3:((ka,6),(l,6),(-))
1:((kb,6),(-),(-))
0:((j,6),(k,6),(-))
1:((h,8),(-),(-))
2:((g,7),(-),(-))
0:((e,5),(f,6),(-))
0:((ba,6),(d,4),(i,9))
1:((ca,6),(-),(-))
1:((c,3),(-),(-))
0:((bb,6),(-),(-))
3:((b,2),(-),(-))
2:((af,6),(-),(-)) <---- will MERGE with Left sibling
0:((aa,6),(ae,6),(ax,6))
1:((ab,6),(-),(-))
0:((a,1),(-),(-))
========================================
Underflow !!!! ===> MERGE with L sibling ((af,6),(-),(-))
== After remove(b):
2:((m,6),(-),(-))
3:((ka,6),(l,6),(-))
1:((kb,6),(-),(-))
0:((j,6),(k,6),(-))
1:((h,8),(-),(-))
2:((g,7),(-),(-))
0:((e,5),(f,6),(-))
0:((ba,6),(d,4),(i,9))
1:((ca,6),(-),(-))
1:((c,3),(-),(-))
0:((bb,6),(-),(-))
2:((af,6),(ax,6),(-))
0:((aa,6),(ae,6),(-))
1:((ab,6),(-),(-))
0:((a,1),(-),(-))
|