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