Mercurial > repos > jjohnson > crest
comparison Tree/Interval.pm @ 0:acc8d8bfeb9a
Uploaded
| author | jjohnson |
|---|---|
| date | Wed, 08 Feb 2012 16:59:24 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:acc8d8bfeb9a |
|---|---|
| 1 package Tree::Interval; | |
| 2 | |
| 3 use strict; | |
| 4 use Carp; | |
| 5 | |
| 6 use Tree::Interval::Node qw[set_color color_of parent_of left_of right_of]; | |
| 7 use Tree::Interval::Node::Constants; | |
| 8 use Tree::DAG_Node; | |
| 9 use vars qw( $VERSION @EXPORT_OK ); | |
| 10 $VERSION = 0.1; | |
| 11 | |
| 12 require Exporter; | |
| 13 *import = \&Exporter::import; | |
| 14 @EXPORT_OK = qw[LUEQUAL LUGTEQ LULTEQ LUGREAT LULESS LUNEXT LUPREV]; | |
| 15 | |
| 16 use enum qw{ LUEQUAL LUGTEQ LULTEQ LUGREAT LULESS LUNEXT LUPREV }; | |
| 17 | |
| 18 # object slots | |
| 19 use enum qw{ ROOT CMP SIZE }; | |
| 20 | |
| 21 sub new { | |
| 22 my ($class, $cmp) = @_; | |
| 23 my $obj = []; | |
| 24 $obj->[SIZE] = 0; | |
| 25 if($cmp) { | |
| 26 ref $cmp eq 'CODE' | |
| 27 or croak('Invalid arg: codref expected'); | |
| 28 $obj->[CMP] = $cmp; | |
| 29 } | |
| 30 else { | |
| 31 # default compare | |
| 32 $obj->[CMP] = sub { $_[0]->[0] <=> $_[1]->[0] || $_[0]->[1] <=> $_[1]->[1]}; | |
| 33 } | |
| 34 return bless $obj => $class; | |
| 35 } | |
| 36 | |
| 37 | |
| 38 sub DESTROY { $_[0]->[ROOT]->DESTROY if $_[0]->[ROOT] } | |
| 39 | |
| 40 sub root { $_[0]->[ROOT] } | |
| 41 sub size { $_[0]->[SIZE] } | |
| 42 | |
| 43 sub left_most { | |
| 44 my $self = shift; | |
| 45 return undef unless $self->[ROOT]; | |
| 46 return $self->[ROOT]->left_most; | |
| 47 } | |
| 48 | |
| 49 sub right_most { | |
| 50 my $self = shift; | |
| 51 return undef unless $self->[ROOT]; | |
| 52 return $self->[ROOT]->right_most; | |
| 53 } | |
| 54 | |
| 55 # return all the intervals intersect with the interval | |
| 56 sub intersect { | |
| 57 my $self = shift; | |
| 58 my $interval = shift; | |
| 59 return my @tmp unless $self->[ROOT]; | |
| 60 return $self->[ROOT]->intersect($interval); | |
| 61 } | |
| 62 | |
| 63 sub lookup { | |
| 64 my $self = shift; | |
| 65 my $key = shift; | |
| 66 defined $key | |
| 67 or croak("Can't use undefined value as key"); | |
| 68 my $mode = shift || LUEQUAL; | |
| 69 my $cmp = $self->[CMP]; | |
| 70 | |
| 71 my $y; | |
| 72 my $x = $self->[ROOT] | |
| 73 or return; | |
| 74 my $next_child; | |
| 75 while($x) { | |
| 76 $y = $x; | |
| 77 if($cmp ? $cmp->($key, $x->[_KEY]) == 0 | |
| 78 : $key eq $x->[_KEY]) { | |
| 79 # found it! | |
| 80 if($mode == LUGREAT || $mode == LUNEXT) { | |
| 81 $x = $x->successor; | |
| 82 } | |
| 83 elsif($mode == LULESS || $mode == LUPREV) { | |
| 84 $x = $x->predecessor; | |
| 85 } | |
| 86 return wantarray | |
| 87 ? ($x->[_VAL], $x) | |
| 88 : $x->[_VAL]; | |
| 89 } | |
| 90 if($cmp ? $cmp->($key, $x->[_KEY]) < 0 | |
| 91 : $key lt $x->[_KEY]) { | |
| 92 $next_child = _LEFT; | |
| 93 } | |
| 94 else { | |
| 95 $next_child = _RIGHT; | |
| 96 } | |
| 97 $x = $x->[$next_child]; | |
| 98 } | |
| 99 # Didn't find it :( | |
| 100 if($mode == LUGTEQ || $mode == LUGREAT) { | |
| 101 if($next_child == _LEFT) { | |
| 102 return wantarray ? ($y->[_VAL], $y) : $y->[_VAL]; | |
| 103 } | |
| 104 else { | |
| 105 my $next = $y->successor | |
| 106 or return; | |
| 107 return wantarray ? ($next->[_VAL], $next) : $next->[_VAL]; | |
| 108 } | |
| 109 } | |
| 110 elsif($mode == LULTEQ || $mode == LULESS) { | |
| 111 if($next_child == _RIGHT) { | |
| 112 return wantarray ? ($y->[_VAL], $y) : $y->[_VAL]; | |
| 113 } | |
| 114 else { | |
| 115 my $next = $y->predecessor | |
| 116 or return; | |
| 117 return wantarray ? ($next->[_VAL], $next) : $next->[_VAL]; | |
| 118 } | |
| 119 } | |
| 120 return; | |
| 121 } | |
| 122 | |
| 123 sub insert { | |
| 124 my $self = shift; | |
| 125 my $key_or_node = shift; | |
| 126 defined $key_or_node | |
| 127 or croak("Can't use undefined value as key or node"); | |
| 128 my $val = shift; | |
| 129 | |
| 130 my $cmp = $self->[CMP]; | |
| 131 my $z = (ref $key_or_node eq 'Tree::Interval::Node') | |
| 132 ? $key_or_node | |
| 133 : Tree::Interval::Node->new($key_or_node => $val); | |
| 134 | |
| 135 my $y; | |
| 136 my $x = $self->[ROOT]; | |
| 137 while($x) { | |
| 138 $y = $x; | |
| 139 # Handle case of inserting node with duplicate key. | |
| 140 if($cmp ? $cmp->($z->[_KEY], $x->[_KEY]) == 0 | |
| 141 : $z->[_KEY] eq $x->[_KEY]) | |
| 142 { | |
| 143 warn "The same key (range) is already in the tree | |
| 144 it will be replaced!"; | |
| 145 my $old_val = $x->[_VAL]; | |
| 146 $x->[_VAL] = $z->[_VAL]; | |
| 147 return $old_val; | |
| 148 } | |
| 149 | |
| 150 if($cmp ? $cmp->($z->[_KEY], $x->[_KEY]) < 0 | |
| 151 : $z->[_KEY] lt $x->[_KEY]) | |
| 152 { | |
| 153 $x = $x->[_LEFT]; | |
| 154 } | |
| 155 else { | |
| 156 $x = $x->[_RIGHT]; | |
| 157 } | |
| 158 } | |
| 159 # insert new node | |
| 160 $z->[_PARENT] = $y; | |
| 161 if(not defined $y) { | |
| 162 $self->[ROOT] = $z; | |
| 163 } | |
| 164 else { | |
| 165 if($cmp ? $cmp->($z->[_KEY], $y->[_KEY]) < 0 | |
| 166 : $z->[_KEY] lt $y->[_KEY]) | |
| 167 { | |
| 168 $y->[_LEFT] = $z; | |
| 169 } | |
| 170 else { | |
| 171 $y->[_RIGHT] = $z; | |
| 172 } | |
| 173 } | |
| 174 _update_max($z); | |
| 175 $self->_fix_after_insertion($z); | |
| 176 $self->[SIZE]++; | |
| 177 } | |
| 178 | |
| 179 sub _fix_after_insertion { | |
| 180 my $self = shift; | |
| 181 my $x = shift or croak('Missing arg: node'); | |
| 182 | |
| 183 $x->[_COLOR] = RED; | |
| 184 while($x != $self->[ROOT] && $x->[_PARENT][_COLOR] == RED) { | |
| 185 my ($child, $rotate1, $rotate2); | |
| 186 if(($x->[_PARENT] || 0) == ($x->[_PARENT][_PARENT][_LEFT] || 0)) { | |
| 187 ($child, $rotate1, $rotate2) = (_RIGHT, '_left_rotate', '_right_rotate'); | |
| 188 } | |
| 189 else { | |
| 190 ($child, $rotate1, $rotate2) = (_LEFT, '_right_rotate', '_left_rotate'); | |
| 191 } | |
| 192 my $y = $x->[_PARENT][_PARENT][$child]; | |
| 193 | |
| 194 if($y && $y->[_COLOR] == RED) { | |
| 195 $x->[_PARENT][_COLOR] = BLACK; | |
| 196 $y->[_COLOR] = BLACK; | |
| 197 $x->[_PARENT][_PARENT][_COLOR] = RED; | |
| 198 $x = $x->[_PARENT][_PARENT]; | |
| 199 } | |
| 200 else { | |
| 201 if($x == ($x->[_PARENT][$child] || 0)) { | |
| 202 $x = $x->[_PARENT]; | |
| 203 $self->$rotate1($x); | |
| 204 } | |
| 205 $x->[_PARENT][_COLOR] = BLACK; | |
| 206 $x->[_PARENT][_PARENT][_COLOR] = RED; | |
| 207 $self->$rotate2($x->[_PARENT][_PARENT]); | |
| 208 } | |
| 209 } | |
| 210 $self->[ROOT][_COLOR] = BLACK; | |
| 211 } | |
| 212 | |
| 213 sub delete { | |
| 214 my ($self, $key_or_node) = @_; | |
| 215 defined $key_or_node | |
| 216 or croak("Can't use undefined value as key or node"); | |
| 217 | |
| 218 my $z = (ref $key_or_node eq 'Tree::Interval::Node') | |
| 219 ? $key_or_node | |
| 220 : ($self->lookup($key_or_node))[1]; | |
| 221 return unless $z; | |
| 222 | |
| 223 my $y; | |
| 224 if($z->[_LEFT] && $z->[_RIGHT]) { | |
| 225 # (Notes kindly provided by Christopher Gurnee) | |
| 226 # When deleting a node 'z' which has two children from a binary search tree, the | |
| 227 # typical algorithm is to delete the successor node 'y' instead (which is | |
| 228 # guaranteed to have at most one child), and then to overwrite the key/values of | |
| 229 # node 'z' (which is still in the tree) with the key/values (which we don't want | |
| 230 # to lose) from the now-deleted successor node 'y'. | |
| 231 | |
| 232 # Since we need to return the deleted item, it's not good enough to overwrite the | |
| 233 # key/values of node 'z' with those of node 'y'. Instead we swap them so we can | |
| 234 # return the deleted values. | |
| 235 | |
| 236 $y = $z->predecessor; | |
| 237 ($z->[_KEY], $y->[_KEY]) = ($y->[_KEY], $z->[_KEY]); | |
| 238 ($z->[_VAL], $y->[_VAL]) = ($y->[_VAL], $z->[_VAL]); | |
| 239 ($z->[_INTERVAL], $y->[_INTERVAL]) = ($y->[_INTERVAL], $z->[_INTERVAL]); | |
| 240 } | |
| 241 else { | |
| 242 $y = $z; | |
| 243 } | |
| 244 | |
| 245 # splice out $y | |
| 246 my $x = $y->[_LEFT] || $y->[_RIGHT]; | |
| 247 if(defined $x) { | |
| 248 $x->[_PARENT] = $y->[_PARENT]; | |
| 249 if(! defined $y->[_PARENT]) { | |
| 250 $self->[ROOT] = $x; | |
| 251 } | |
| 252 elsif($y == $y->[_PARENT][_LEFT]) { | |
| 253 $y->[_PARENT][_LEFT] = $x; | |
| 254 } | |
| 255 else { | |
| 256 $y->[_PARENT][_RIGHT] = $x; | |
| 257 } | |
| 258 # Null out links so they are OK to use by _fix_after_deletion | |
| 259 delete @{$y}[_PARENT, _LEFT, _RIGHT]; | |
| 260 _update_max($x); | |
| 261 # Fix replacement | |
| 262 if($y->[_COLOR] == BLACK) { | |
| 263 $self->_fix_after_deletion($x); | |
| 264 } | |
| 265 } | |
| 266 elsif(! defined $y->[_PARENT]) { | |
| 267 # return if we are the only node | |
| 268 delete $self->[ROOT]; | |
| 269 } | |
| 270 else { | |
| 271 # No children. Use self as phantom replacement and unlink | |
| 272 if($y->[_COLOR] == BLACK) { | |
| 273 $self->_fix_after_deletion($y); | |
| 274 } | |
| 275 if(defined $y->[_PARENT]) { | |
| 276 no warnings 'uninitialized'; | |
| 277 if($y == $y->[_PARENT][_LEFT]) { | |
| 278 delete $y->[_PARENT][_LEFT]; | |
| 279 } | |
| 280 elsif($y == $y->[_PARENT][_RIGHT]) { | |
| 281 delete $y->[_PARENT][_RIGHT]; | |
| 282 } | |
| 283 my $tmp = $y->[_PARENT]; | |
| 284 delete $y->[_PARENT]; | |
| 285 _update_max($tmp); | |
| 286 } | |
| 287 } | |
| 288 $self->[SIZE]--; | |
| 289 return $y; | |
| 290 } | |
| 291 | |
| 292 sub _fix_after_deletion { | |
| 293 my $self = shift; | |
| 294 my $x = shift or croak('Missing arg: node'); | |
| 295 | |
| 296 while($x != $self->[ROOT] && color_of($x) == BLACK) { | |
| 297 my ($child1, $child2, $rotate1, $rotate2); | |
| 298 no warnings 'uninitialized'; | |
| 299 if($x == left_of(parent_of($x))) { | |
| 300 ($child1, $child2, $rotate1, $rotate2) = | |
| 301 (\&right_of, \&left_of, '_left_rotate', '_right_rotate'); | |
| 302 } | |
| 303 else { | |
| 304 ($child1, $child2, $rotate1, $rotate2) = | |
| 305 (\&left_of, \&right_of, '_right_rotate', '_left_rotate'); | |
| 306 } | |
| 307 use warnings; | |
| 308 | |
| 309 my $w = $child1->(parent_of($x)); | |
| 310 if(color_of($w) == RED) { | |
| 311 set_color($w, BLACK); | |
| 312 set_color(parent_of($x), RED); | |
| 313 $self->$rotate1(parent_of($x)); | |
| 314 $w = right_of(parent_of($x)); | |
| 315 } | |
| 316 if(color_of($child2->($w)) == BLACK && | |
| 317 color_of($child1->($w)) == BLACK) { | |
| 318 set_color($w, RED); | |
| 319 $x = parent_of($x); | |
| 320 } | |
| 321 else { | |
| 322 if(color_of($child1->($w)) == BLACK) { | |
| 323 set_color($child2->($w), BLACK); | |
| 324 set_color($w, RED); | |
| 325 $self->$rotate2($w); | |
| 326 $w = $child1->(parent_of($x)); | |
| 327 } | |
| 328 set_color($w, color_of(parent_of($x))); | |
| 329 set_color(parent_of($x), BLACK); | |
| 330 set_color($child1->($w), BLACK); | |
| 331 $self->$rotate1(parent_of($x)); | |
| 332 $x = $self->[ROOT]; | |
| 333 } | |
| 334 } | |
| 335 set_color($x, BLACK); | |
| 336 } | |
| 337 | |
| 338 | |
| 339 sub _max3 { | |
| 340 my ($a, $b, $c) = @_; | |
| 341 my $min = ($a || $b || $c) - 1; | |
| 342 $a = $a || $min; | |
| 343 $b = $b || $min; | |
| 344 $c = $c || $min; | |
| 345 return $a if($a >= $b && $a >= $c); | |
| 346 return $b if($b >= $a && $b >= $c); | |
| 347 return $c if($c >= $a && $c >= $b); | |
| 348 } | |
| 349 | |
| 350 sub _max { | |
| 351 my $x = shift; | |
| 352 my $tmp = _max3($x->[_INTERVAL][1], | |
| 353 $x->[_LEFT] ? $x->[_LEFT][_MAX] : undef, | |
| 354 $x->[_RIGHT] ? $x->[_RIGHT][_MAX] : undef); | |
| 355 $x->[_MAX] = $tmp; | |
| 356 return $tmp; | |
| 357 } | |
| 358 | |
| 359 sub _update_max { | |
| 360 my $x = shift; | |
| 361 #update the max field for each parent node | |
| 362 _max($x); | |
| 363 my $k = $x->[_PARENT]; | |
| 364 while($k) { | |
| 365 my $tmp = $k->[_MAX]; | |
| 366 _max($k); | |
| 367 last if($tmp == $k->[_MAX]); # no need to update further | |
| 368 $k = $k->[_PARENT]; | |
| 369 } | |
| 370 } | |
| 371 | |
| 372 sub _left_rotate { | |
| 373 my $self = shift; | |
| 374 my $x = shift or croak('Missing arg: node'); | |
| 375 | |
| 376 my $y = $x->[_RIGHT] | |
| 377 or return; | |
| 378 $x->[_RIGHT] = $y->[_LEFT]; | |
| 379 if($y->[_LEFT]) { | |
| 380 $y->[_LEFT]->[_PARENT] = $x; | |
| 381 } | |
| 382 $y->[_PARENT] = $x->[_PARENT]; | |
| 383 if(not defined $x->[_PARENT]) { | |
| 384 $self->[ROOT] = $y; | |
| 385 } | |
| 386 else { | |
| 387 $x == $x->[_PARENT]->[_LEFT] | |
| 388 ? $x->[_PARENT]->[_LEFT] = $y | |
| 389 : $x->[_PARENT]->[_RIGHT] = $y; | |
| 390 } | |
| 391 $y->[_LEFT] = $x; | |
| 392 $x->[_PARENT] = $y; | |
| 393 #update max | |
| 394 _max($x); _max($y); | |
| 395 } | |
| 396 | |
| 397 sub _right_rotate { | |
| 398 my $self = shift; | |
| 399 my $y = shift or croak('Missing arg: node'); | |
| 400 | |
| 401 my $x = $y->[_LEFT] | |
| 402 or return; | |
| 403 $y->[_LEFT] = $x->[_RIGHT]; | |
| 404 if($x->[_RIGHT]) { | |
| 405 $x->[_RIGHT]->[_PARENT] = $y | |
| 406 } | |
| 407 $x->[_PARENT] = $y->[_PARENT]; | |
| 408 if(not defined $y->[_PARENT]) { | |
| 409 $self->[ROOT] = $x; | |
| 410 } | |
| 411 else { | |
| 412 $y == $y->[_PARENT]->[_RIGHT] | |
| 413 ? $y->[_PARENT]->[_RIGHT] = $x | |
| 414 : $y->[_PARENT]->[_LEFT] = $x; | |
| 415 } | |
| 416 $x->[_RIGHT] = $y; | |
| 417 $y->[_PARENT] = $x; | |
| 418 _max($y); _max($x); | |
| 419 } | |
| 420 | |
| 421 1; | |
| 422 | |
| 423 # Magic true value required at end of module | |
| 424 __END__ | |
| 425 | |
| 426 =head1 NAME | |
| 427 | |
| 428 Tree::RB - Perl implementation of the Red/Black tree, a type of balanced binary search tree. | |
| 429 | |
| 430 | |
| 431 =head1 VERSION | |
| 432 | |
| 433 This document describes Tree::RB version 0.1 | |
| 434 | |
| 435 | |
| 436 =head1 SYNOPSIS | |
| 437 | |
| 438 use Tree::RB; | |
| 439 | |
| 440 my $tree = Tree::RB->new; | |
| 441 $tree->put('France' => 'Paris'); | |
| 442 $tree->put('England' => 'London'); | |
| 443 $tree->put('Hungary' => 'Budapest'); | |
| 444 $tree->put('Ireland' => 'Dublin'); | |
| 445 $tree->put('Egypt' => 'Cairo'); | |
| 446 $tree->put('Germany' => 'Berlin'); | |
| 447 | |
| 448 $tree->put('Alaska' => 'Anchorage'); # D'oh! | |
| 449 $tree->delete('Alaska'); | |
| 450 | |
| 451 print $tree->get('Ireland'); # 'Dublin' | |
| 452 | |
| 453 print $tree->min->key; # 'Egypt' | |
| 454 print $tree->max->key; # 'Ireland' | |
| 455 print $tree->size; # 6 | |
| 456 | |
| 457 # print items, ordered by key | |
| 458 my $it = $tree->iter; | |
| 459 | |
| 460 while(my $node = $it->next) { | |
| 461 sprintf "key = %s, value = %s\n", $node->key, $node->val; | |
| 462 } | |
| 463 | |
| 464 # print items in reverse order | |
| 465 $it = $tree->rev_iter; | |
| 466 | |
| 467 while(my $node = $it->next) { | |
| 468 sprintf "key = %s, value = %s\n", $node->key, $node->val; | |
| 469 } | |
| 470 | |
| 471 # Hash interface | |
| 472 tie my %capital, 'Tree::RB'; | |
| 473 | |
| 474 # or do this to store items in descending order | |
| 475 tie my %capital, 'Tree::RB', sub { $_[1] cmp $_[0] }; | |
| 476 | |
| 477 $capital{'France'} = 'Paris'; | |
| 478 $capital{'England'} = 'London'; | |
| 479 $capital{'Hungary'} = 'Budapest'; | |
| 480 $capital{'Ireland'} = 'Dublin'; | |
| 481 $capital{'Egypt'} = 'Cairo'; | |
| 482 $capital{'Germany'} = 'Berlin'; | |
| 483 | |
| 484 # print items in order | |
| 485 while(my ($key, $val) = each %capital) { | |
| 486 printf "key = $key, value = $val\n"; | |
| 487 } | |
| 488 | |
| 489 =head1 DESCRIPTION | |
| 490 | |
| 491 This is a Perl implementation of the Red/Black tree, a type of balanced binary search tree. | |
| 492 | |
| 493 A tied hash interface is also provided to allow ordered hashes to be used. | |
| 494 | |
| 495 See the Wikipedia article at L<http://en.wikipedia.org/wiki/Red-black_tree> for more on Red/Black trees. | |
| 496 | |
| 497 | |
| 498 =head1 INTERFACE | |
| 499 | |
| 500 =head2 new([CODEREF]) | |
| 501 | |
| 502 Creates and returns a new tree. If a reference to a subroutine is passed to | |
| 503 new(), the subroutine will be used to override the tree's default lexical | |
| 504 ordering and provide a user a defined ordering. | |
| 505 | |
| 506 This subroutine should be just like a comparator subroutine used with L<sort>, | |
| 507 except that it doesn't do the $a, $b trick. | |
| 508 | |
| 509 For example, to get a case insensitive ordering | |
| 510 | |
| 511 my $tree = Tree::RB->new(sub { lc $_[0] cmp lc $_[1]}); | |
| 512 $tree->put('Wall' => 'Larry'); | |
| 513 $tree->put('Smith' => 'Agent'); | |
| 514 $tree->put('mouse' => 'micky'); | |
| 515 $tree->put('duck' => 'donald'); | |
| 516 | |
| 517 my $it = $tree->iter; | |
| 518 | |
| 519 while(my $node = $it->next) { | |
| 520 sprintf "key = %s, value = %s\n", $node->key, $node->val; | |
| 521 } | |
| 522 | |
| 523 =head2 resort(CODEREF) | |
| 524 | |
| 525 Changes the ordering of nodes within the tree. The new ordering is | |
| 526 specified by a comparator subroutine which must be passed to resort(). | |
| 527 | |
| 528 See L</new> for further information about the comparator. | |
| 529 | |
| 530 =head2 size() | |
| 531 | |
| 532 Returns the number of nodes in the tree. | |
| 533 | |
| 534 =head2 root() | |
| 535 | |
| 536 Returns the root node of the tree. This will either be undef | |
| 537 if no nodes have been added to the tree, or a L<Tree::RB::Node> object. | |
| 538 See the L<Tree::RB::Node> manual page for details on the Node object. | |
| 539 | |
| 540 =head2 min() | |
| 541 | |
| 542 Returns the node with the minimal key. | |
| 543 | |
| 544 =head2 max() | |
| 545 | |
| 546 Returns the node with the maximal key. | |
| 547 | |
| 548 =head2 lookup(KEY, [MODE]) | |
| 549 | |
| 550 When called in scalar context, lookup(KEY) returns the value | |
| 551 associated with KEY. | |
| 552 | |
| 553 When called in list context, lookup(KEY) returns a list whose first | |
| 554 element is the value associated with KEY, and whose second element | |
| 555 is the node containing the key/value. | |
| 556 | |
| 557 An optional MODE parameter can be passed to lookup() to influence | |
| 558 which key is returned. | |
| 559 | |
| 560 The values of MODE are constants that are exported on demand by | |
| 561 Tree::RB | |
| 562 | |
| 563 use Tree::RB qw[LUEQUAL LUGTEQ LULTEQ LUGREAT LULESS LUNEXT LUPREV]; | |
| 564 | |
| 565 =over | |
| 566 | |
| 567 =item LUEQUAL | |
| 568 | |
| 569 Returns node exactly matching the key. | |
| 570 | |
| 571 =item LUGTEQ | |
| 572 | |
| 573 Returns the node exactly matching the specified key, | |
| 574 if this is not found then the next node that is greater than the specified key is returned. | |
| 575 | |
| 576 =item LULTEQ | |
| 577 | |
| 578 Returns the node exactly matching the specified key, | |
| 579 if this is not found then the next node that is less than the specified key is returned. | |
| 580 | |
| 581 =item LUGREAT | |
| 582 | |
| 583 Returns the node that is just greater than the specified key - not equal to. | |
| 584 This mode is similar to LUNEXT except that the specified key need not exist in the tree. | |
| 585 | |
| 586 =item LULESS | |
| 587 | |
| 588 Returns the node that is just less than the specified key - not equal to. | |
| 589 This mode is similar to LUPREV except that the specified key need not exist in the tree. | |
| 590 | |
| 591 =item LUNEXT | |
| 592 | |
| 593 Looks for the key specified, if not found returns C<undef>. | |
| 594 If the node is found returns the next node that is greater than | |
| 595 the one found (or C<undef> if there is no next node). | |
| 596 | |
| 597 This can be used to step through the tree in order. | |
| 598 | |
| 599 =item LUPREV | |
| 600 | |
| 601 Looks for the key specified, if not found returns C<undef>. | |
| 602 If the node is found returns the previous node that is less than | |
| 603 the one found (or C<undef> if there is no previous node). | |
| 604 | |
| 605 This can be used to step through the tree in reverse order. | |
| 606 | |
| 607 =back | |
| 608 | |
| 609 =head2 get(KEY) | |
| 610 | |
| 611 get() is an alias for lookup(). | |
| 612 | |
| 613 =head2 iter([KEY]) | |
| 614 | |
| 615 Returns an iterator object that can be used to traverse the tree in order. | |
| 616 | |
| 617 The iterator object supports a 'next' method that returns the next node in the | |
| 618 tree or undef if all of the nodes have been visited. | |
| 619 | |
| 620 See the synopsis for an example. | |
| 621 | |
| 622 If a key is supplied, the iterator returned will traverse the tree in order starting from | |
| 623 the node with key greater than or equal to the specified key. | |
| 624 | |
| 625 $it = $tree->iter('France'); | |
| 626 my $node = $it->next; | |
| 627 print $node->key; # -> 'France' | |
| 628 | |
| 629 =head2 rev_iter([KEY]) | |
| 630 | |
| 631 Returns an iterator object that can be used to traverse the tree in reverse order. | |
| 632 | |
| 633 If a key is supplied, the iterator returned will traverse the tree in order starting from | |
| 634 the node with key less than or equal to the specified key. | |
| 635 | |
| 636 $it = $tree->rev_iter('France'); | |
| 637 my $node = $it->next; | |
| 638 print $node->key; # -> 'England' | |
| 639 | |
| 640 =head2 hseek(KEY, [{-reverse => 1|0}]) | |
| 641 | |
| 642 For tied hashes, determines the next entry to be returned by each. | |
| 643 | |
| 644 tie my %capital, 'Tree::RB'; | |
| 645 | |
| 646 $capital{'France'} = 'Paris'; | |
| 647 $capital{'England'} = 'London'; | |
| 648 $capital{'Hungary'} = 'Budapest'; | |
| 649 $capital{'Ireland'} = 'Dublin'; | |
| 650 $capital{'Egypt'} = 'Cairo'; | |
| 651 $capital{'Germany'} = 'Berlin'; | |
| 652 tied(%capital)->hseek('Germany'); | |
| 653 | |
| 654 ($key, $val) = each %capital; | |
| 655 print "$key, $val"; # -> Germany, Berlin | |
| 656 | |
| 657 The direction of iteration can be reversed by passing a hashref with key '-reverse' and value 1 | |
| 658 to hseek after or instead of KEY, e.g. to iterate over the hash in reverse order: | |
| 659 | |
| 660 tied(%capital)->hseek({-reverse => 1}); | |
| 661 $key = each %capital; | |
| 662 print $key; # -> Ireland | |
| 663 | |
| 664 The following calls are equivalent | |
| 665 | |
| 666 tied(%capital)->hseek('Germany', {-reverse => 1}); | |
| 667 tied(%capital)->hseek({-key => 'Germany', -reverse => 1}); | |
| 668 | |
| 669 =head2 put(KEY, VALUE) | |
| 670 | |
| 671 Adds a new node to the tree. | |
| 672 | |
| 673 The first argument is the key of the node, the second is its value. | |
| 674 | |
| 675 If a node with that key already exists, its value is replaced with | |
| 676 the given value and the old value is returned. Otherwise, undef is returned. | |
| 677 | |
| 678 =head2 delete(KEY) | |
| 679 | |
| 680 If the tree has a node with the specified key, that node is | |
| 681 deleted from the tree and returned, otherwise C<undef> is returned. | |
| 682 | |
| 683 | |
| 684 =head1 DEPENDENCIES | |
| 685 | |
| 686 L<enum> | |
| 687 | |
| 688 | |
| 689 =head1 INCOMPATIBILITIES | |
| 690 | |
| 691 None reported. | |
| 692 | |
| 693 | |
| 694 =head1 BUGS AND LIMITATIONS | |
| 695 | |
| 696 Please report any bugs or feature requests to | |
| 697 C<bug-tree-rb@rt.cpan.org>, or through the web interface at | |
| 698 L<http://rt.cpan.org>. | |
| 699 | |
| 700 | |
| 701 =head1 AUTHOR | |
| 702 | |
| 703 Arun Prasad C<< <arunbear@cpan.org> >> | |
| 704 | |
| 705 Some documentation has been borrowed from Benjamin Holzman's L<Tree::RedBlack> | |
| 706 and Damian Ivereigh's libredblack (L<http://libredblack.sourceforge.net/>). | |
| 707 | |
| 708 =head1 ACKNOWLEDGEMENTS | |
| 709 | |
| 710 Thanks for bug reports go to Anton Petrusevich, Wes Thompson and Christopher Gurnee. | |
| 711 | |
| 712 =head1 LICENCE AND COPYRIGHT | |
| 713 | |
| 714 Copyright (c) 2007, Arun Prasad C<< <arunbear@cpan.org> >>. All rights reserved. | |
| 715 | |
| 716 This module is free software; you can redistribute it and/or | |
| 717 modify it under the same terms as Perl itself. See L<perlartistic>. | |
| 718 | |
| 719 | |
| 720 =head1 DISCLAIMER OF WARRANTY | |
| 721 | |
| 722 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |
| 723 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |
| 724 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |
| 725 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER | |
| 726 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 727 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE | |
| 728 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH | |
| 729 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL | |
| 730 NECESSARY SERVICING, REPAIR, OR CORRECTION. | |
| 731 | |
| 732 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
| 733 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |
| 734 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE | |
| 735 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, | |
| 736 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE | |
| 737 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | |
| 738 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | |
| 739 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF | |
| 740 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | |
| 741 SUCH DAMAGES. |
