comparison Tree/Interval/Node.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::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