Friday, November 30, 2007

PHP B-tree - Remove element/node

Here follows an example of deleting from "Multiway B-Tree".

PHP code:



function btree_delete($value, $a, &$higher)
{
/* search and delete key $value in B-tree a; if a page underflow arises,
balance with adjacent page or merge; $higher := "page $a is undersize" */

global $tree, $n;

if( $a === null )
{
$higher = false;
}
else
{
$l = 1;
$r = $tree[$a]['m'];

// binary search
do
{
$k = (int)( ($l + $r)/2 );
if( $value <= $tree[$a]['el'][$k]['value'] )
$r = $k -1;
if( $value >= $tree[$a]['el'][$k]['value'] )
$l = $k +1;
}while( $r >= $l );


if( $r === 0 )
{
$q = $tree[$a]['p0']; // go to the left
}
else
$q = $tree[$a]['el'][$r]['p']; // go to the right

if( $l - $r > 1)
{
// $a is leaf page
if( $q === null )
{
$tree[$a]['m']--;
$higher = ($tree[$a]['m'] < $n )? true: false;

for( $i=$k; $i <= $tree[$a]['m']; $i++ )
{
$tree[$a]['el'][$i] = $tree[$a]['el'][$i+1];
}
}
else
{
btree_del($q,$a, $higher, $k);
if( $higher )
{
underflow( $a , $q, $r, $higher, $k);
}
}
}
else
{
btree_delete( $value, $q, $higher );
if( $higher )
{
underflow( $a, $q, $r, $higher, $k );
}
}
}

}

function underflow( $c, $a, $s, &$higher, &$k )
{
/* $a = underflowing page, $c = ancestor page,
$s = index of deleted entry in c */

global $tree, $n;

$mc = $tree[$c]['m'];

if( $s < $mc )
{
$s++;

// $b = page to the right of a
$b = $tree[$c]['el'][$s]['p'];
$mb = $tree[$b]['m'];

// $k = nof items available on page b
$k = (int)( ($mb - $n+1)/2 );

$tree[$a]['el'][$n] = $tree[$c]['el'][$s];

$tree[$a]['el'][$n]['p'] = $tree[$b]['p0'];

if( $k > 0 )// balance by moving k-1 items from $b to $a
{
for( $i=1; $i <= $k-1; $i++ )
{
$tree[$a]['el'][$i+$n] = $tree[$b]['el'][$i];
}
$tree[$c]['el'][$s] = $tree[$b]['el'][$k];
$tree[$c]['el'][$s]['p'] = $b;

$tree[$b]['p0'] = $tree[$b]['el'][$k]['p'];
$mb -= $k;/////// +1

for( $i=1; $i <= $mb; $i++ )
{
$tree[$b]['el'][$i] = $tree[$b]['el'][$i+$k];
}
$tree[$b]['m'] = $mb;
$tree[$a]['m'] = $n-1 +$k;
$higher = false;

}
else// merging a and b, discard b
{
for( $i=1; $i <= $n; $i++ )
{
$tree[$a]['el'][$i+$n] = $tree[$b]['el'][$i];
}
for( $i=$s; $i <= $mc-1; $i++)
{
$tree[$c]['el'][$i] = $tree[$c]['el'][$i+1];
}
$tree[$a]['m'] = 2*$n;
$tree[$c]['m'] = $mc - 1;
}
}
else
{
// $b = page to the left of $a
if( $s == 1 )
{
$b = $tree[$c]['p0'];
}
else
{
$b = $tree[$c]['el'][$s-1]['p'];
}
$mb = $tree[$b]['m']+1;
$k = (int)( ($mb - $n)/2 );

if( $k > 0 )
{
for( $i=$n-1; $i >= 1; $i-- )
{
$tree[$a]['el'][$i+$k] = $tree[$a]['el'][$i];
}
$tree[$a]['el'][$k] = $tree[$c]['el'][$s];
$tree[$a]['el'][$k]['p'] = $tree[$a]['p0'];

// move k-1 items from $b to $a, one to $c

$mb -= $k;//////// +1

for( $i=$k-1; $i >= 1; $i-- )
{
$tree[$a]['el'][$i] = $tree[$b]['el'][$i+$mb];
}
$tree[$a]['p0'] = $tree[$b]['el'][$mb]['p'];

$tree[$c]['el'][$s] = $tree[$b]['el'][$mb];
$tree[$c]['el'][$s]['p'] = $a;

$tree[$b]['m'] = $mb -1;
$tree[$a]['m'] = $n-1 +$k;

$higher = false;

}
else //merge pages $a and $b, discard $a
{
$tree[$b]['el'][$mb] = $tree[$c]['el'][$s];
$tree[$b]['el'][$mb]['p'] = $tree[$a]['p0'];

for( $i=1; $i <= $n-1; $i++ )
{
$tree[$b]['el'][$i+$mb] = $tree[$a]['el'][$i];
}
$tree[$b]['m'] = 2*$n;
$tree[$c]['m'] = $mc - 1;
}
}
}

function btree_del($p, $a, &$higher, &$k)
{
global $tree, $n;

$m = &$tree[$p]['m'];

$q = $tree[$p]['el'][$m]['p'];
if( $q !== null )
{
btree_del($q, $a, $higher, $k);
if( $higher )
underflow($p, $q, $m, $higher, $k);
}
else
{
$tree[$p]['el'][$m]['p'] = $tree[$a]['el'][$k]['p'];
$tree[$a]['el'][$k] = $tree[$p]['el'][$m];

$m--;

$higher = ($m < $n )? true: false;
}
}



Full example of creating and delete from B-Tree here

No comments: