| 0 | 1 package Tree::Interval::Node; | 
|  | 2 | 
|  | 3 use strict; | 
|  | 4 use Carp; | 
|  | 5 use Tree::Interval::Node::Constants; | 
|  | 6 use vars qw( $VERSION @EXPORT_OK ); | 
|  | 7 | 
|  | 8 require Exporter; | 
|  | 9 *import    = \&Exporter::import; | 
|  | 10 @EXPORT_OK = qw[set_color color_of parent_of left_of right_of]; | 
|  | 11 | 
|  | 12 $VERSION = '0.1'; | 
|  | 13 | 
|  | 14 # key and interval is the same thing | 
|  | 15 my %attribute = ( | 
|  | 16     key    => _KEY, | 
|  | 17     val    => _VAL, | 
|  | 18     color  => _COLOR, | 
|  | 19     parent => _PARENT, | 
|  | 20     left   => _LEFT, | 
|  | 21     right  => _RIGHT, | 
|  | 22 	max    => _MAX, | 
|  | 23 	interval => _INTERVAL, | 
|  | 24 ); | 
|  | 25 | 
|  | 26 #using an array instead of a hash for the node | 
|  | 27 sub _accessor { | 
|  | 28     my $index = shift; | 
|  | 29     return sub { | 
|  | 30         my $self = shift; | 
|  | 31 		return undef unless $self; | 
|  | 32         if (@_) { | 
|  | 33           $self->[$index] = shift; | 
|  | 34         } | 
|  | 35         return $self->[$index]; | 
|  | 36     }; | 
|  | 37 } | 
|  | 38 | 
|  | 39 while(my($at, $idx) = each %attribute) { | 
|  | 40     no strict 'refs'; | 
|  | 41     *$at = _accessor($idx); | 
|  | 42 } | 
|  | 43 | 
|  | 44 sub new { | 
|  | 45     my $class = shift; | 
|  | 46     my $obj = []; | 
|  | 47 | 
|  | 48     if (@_) { | 
|  | 49         $obj->[_KEY] = $obj->[_INTERVAL] = shift; | 
|  | 50         $obj->[_VAL] = shift; | 
|  | 51     } | 
|  | 52     return bless $obj, $class; | 
|  | 53 } | 
|  | 54 | 
|  | 55 sub left_most { | 
|  | 56     my $self = shift; | 
|  | 57     while ($self->[_LEFT]) { | 
|  | 58         $self = $self->[_LEFT]; | 
|  | 59     } | 
|  | 60     return $self; | 
|  | 61 } | 
|  | 62 | 
|  | 63 sub right_most { | 
|  | 64     my $self = shift; | 
|  | 65     while ($self->[_RIGHT]) { | 
|  | 66         $self = $self->[_RIGHT]; | 
|  | 67     } | 
|  | 68     return $self; | 
|  | 69 } | 
|  | 70 | 
|  | 71 #find left_most leaf | 
|  | 72 sub leaf { | 
|  | 73     my $self = shift; | 
|  | 74     while (my $any_child = $self->[_LEFT] || $self->[_RIGHT]) { | 
|  | 75         $self = $any_child; | 
|  | 76     } | 
|  | 77     return $self; | 
|  | 78 } | 
|  | 79 | 
|  | 80 sub successor { | 
|  | 81     my $self = shift; | 
|  | 82     if ($self->[_RIGHT]) { | 
|  | 83         return $self->[_RIGHT]->left_most; | 
|  | 84     } | 
|  | 85     my $parent = $self->[_PARENT]; | 
|  | 86     while ($parent && $parent->[_RIGHT] && $self == $parent->[_RIGHT]) { | 
|  | 87         $self = $parent; | 
|  | 88         $parent = $parent->[_PARENT]; | 
|  | 89     } | 
|  | 90     return $parent; | 
|  | 91 } | 
|  | 92 | 
|  | 93 sub predecessor { | 
|  | 94     my $self = shift; | 
|  | 95     if ($self->[_LEFT]) { | 
|  | 96         return $self->[_LEFT]->right_most; | 
|  | 97     } | 
|  | 98     my $parent = $self->[_PARENT]; | 
|  | 99     while ($parent && $parent->[_LEFT] && $self == $parent->[_LEFT]) { | 
|  | 100         $self = $parent; | 
|  | 101         $parent = $parent->[_PARENT]; | 
|  | 102     } | 
|  | 103     return $parent; | 
|  | 104 } | 
|  | 105 | 
|  | 106 sub as_lol { | 
|  | 107     my $self = shift; | 
|  | 108     my $node = shift || $self; | 
|  | 109     my $aref; | 
|  | 110     push @$aref, | 
|  | 111          $node->[_LEFT] | 
|  | 112            ? $self->as_lol($node->[_LEFT]) | 
|  | 113            : '*'; | 
|  | 114     push @$aref, | 
|  | 115          $node->[_RIGHT] | 
|  | 116            ? $self->as_lol($node->[_RIGHT]) | 
|  | 117            : '*'; | 
|  | 118     my $color = ($node->[_COLOR] == RED ? 'R' : 'B'); | 
|  | 119     no warnings 'uninitialized'; | 
|  | 120     push @$aref, "$color:[$node->[_KEY][0],$node->[_KEY][1]]:$node->[_MAX]"; | 
|  | 121     return $aref; | 
|  | 122 } | 
|  | 123 | 
|  | 124 sub strip { | 
|  | 125     my $self = shift; | 
|  | 126     my $callback = shift; | 
|  | 127 | 
|  | 128     my $x = $self; | 
|  | 129     while($x) { | 
|  | 130         my $leaf = $x->leaf; | 
|  | 131         $x = $leaf->[_PARENT]; | 
|  | 132 | 
|  | 133         # detach $leaf from the (sub)tree | 
|  | 134         no warnings "uninitialized"; | 
|  | 135         if($leaf == $x->[_LEFT]) { | 
|  | 136             undef $x->[_LEFT]; | 
|  | 137         } | 
|  | 138         else { | 
|  | 139             undef $x->[_RIGHT]; | 
|  | 140         } | 
|  | 141         undef $leaf->[_PARENT]; | 
|  | 142         if($callback) { | 
|  | 143             $callback->($leaf); | 
|  | 144         } | 
|  | 145 | 
|  | 146         if(!$x->[_LEFT] && !$x->[_RIGHT]) { | 
|  | 147             $x = $x->[_PARENT]; | 
|  | 148         } | 
|  | 149     } | 
|  | 150 } | 
|  | 151 | 
|  | 152 sub DESTROY { $_[0]->strip; } | 
|  | 153 | 
|  | 154 # Null aware accessors to assist with rebalancings during insertion and deletion | 
|  | 155 # | 
|  | 156 # A weird case of Java to the rescue! | 
|  | 157 # These are inspired by http://www.javaresearch.org/source/jdk142/java/util/TreeMap.java.html | 
|  | 158 # which was found via http://en.wikipedia.org/wiki/Red-black_tree#Implementations | 
|  | 159 | 
|  | 160 # do wen need it? as we have accessors already | 
|  | 161 sub set_color { | 
|  | 162     my ($node, $color) = @_; | 
|  | 163     if($node) { | 
|  | 164         $node->[_COLOR] = $color; | 
|  | 165     } | 
|  | 166 } | 
|  | 167 | 
|  | 168 sub color_of { | 
|  | 169     $_[0] ? $_[0]->[_COLOR] : BLACK; | 
|  | 170 } | 
|  | 171 | 
|  | 172 sub parent_of { | 
|  | 173     $_[0] ? $_[0]->[_PARENT] : undef; | 
|  | 174 } | 
|  | 175 | 
|  | 176 sub left_of { | 
|  | 177     $_[0] ? $_[0]->[_LEFT] : undef; | 
|  | 178 } | 
|  | 179 | 
|  | 180 sub right_of { | 
|  | 181     $_[0] ? $_[0]->[_RIGHT] : undef; | 
|  | 182 } | 
|  | 183 | 
|  | 184 sub _overlap { | 
|  | 185 	my ($a, $b) = @_; | 
|  | 186 	return 1 if($a->[0] <= $b->[1] && $a->[1] >= $b->[0]); | 
|  | 187 	return undef; | 
|  | 188 } | 
|  | 189 | 
|  | 190 sub intersect { | 
|  | 191 	my $x = shift; | 
|  | 192 	my $interval = shift; | 
|  | 193 	return if(!$x); | 
|  | 194 #	print $x->val->name, "\t", $x->key->[0], "\t", $x->key->[1], "\n"; | 
|  | 195 	my @rtn; | 
|  | 196 	if(_overlap($x->interval, $interval)) { | 
|  | 197 		push @rtn, $x; | 
|  | 198 	} | 
|  | 199 #	my $y = $x->parent; | 
|  | 200 	if($x->left && $x->left->max >= $interval->[0] ) { # && (!$y || _overlap($interval, [$y->interval->[0], $x->left->max]))) { | 
|  | 201 		push @rtn, $x->left->intersect($interval); | 
|  | 202 	} | 
|  | 203 	push @rtn, $x->right->intersect($interval) if($x->right && _overlap($interval, [$x->interval->[0], $x->right->max])); | 
|  | 204 	return @rtn; | 
|  | 205 } | 
|  | 206 | 
|  | 207 1; | 
|  | 208 |