0
|
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.
|