3 See the NOTICE file distributed with
this work
for additional information
4 regarding copyright ownership.
6 Licensed under the Apache License, Version 2.0 (the
"License");
7 you may not use
this file except in compliance with the License.
8 You may obtain a copy of the License at
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an
"AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License
for the specific language governing permissions and
16 limitations under the License.
23 Please email comments or questions to the
public Ensembl
24 developers list at <http:
26 Questions may also be sent to the Ensembl help desk at
37 Pure Perl fall back implementation of a
mutable interval tree, uses
38 augmented AVL binary balanced trees.
44 package Bio::EnsEMBL::Utils::Tree::Interval::Mutable::PP;
56 Example : my $tree = Bio::EnsEMBL::Utils::Tree::Mutable();
57 Description : Constructor. Creates a
new mutable tree instance
66 my $class = ref($caller) || $caller;
68 # mmhh, should probably return just the hash ref
69 return bless({ _root => undef, _size => 0 }, $class);
75 Example : my $root = $tree->
root;
76 Description : Returns the tree top node
85 $self->{_root} = shift
if( @_ );
87 return $self->{_root};
93 Example : print
"Tree size is ", $tree->size,
"\n";
94 Description : Return the size of the tree, i.e. the number of nodes
102 return shift->{_size};
110 Description : Insert an interval in the tree
111 Returntype : scalar (1), upon success
112 Exceptions : thrown
if Interval spans origin (has start > end)
120 if ($i->spans_origin) {
121 throw "Cannot insert an interval that spans the origin into a mutable tree";
123 # base case: empty tree, assign new node to root
124 unless (defined $self->root) {
131 # check if node exists with the same key
132 my $node = $self->root->search_by_key($i->start);
134 # check the node's intervals if there's already one
135 # which is the same as the interval we're trying to insert
136 map {
return 0
if $_->start == $i->start and $_->end == $i->end } @{$node->intervals};
138 # add the interval to the node
139 $node->add_interval($i);
141 # update max of node and its ancestors if necessary
142 if ($node->max < $i->end) {
144 $node->_update_parents_max
if $node->parent;
151 # node with the interval's key doesn't exist
152 # insert from root node
153 $self->root->insert($i);
159 croak
"Shouldn't be here";
164 Arg [1] : scalar, $start
165 the starting point of the interval to search
166 Arg [2] : scalar, $end
167 the end point of the interval to search
168 Example : my $result = $tree->search(85, 100);
169 Description : Search the intervals in the tree overlapping the query
177 my ($self, $start, $end) = @_;
179 return unless $self->root; # empty tree
187 The interval to remove from the tree
188 Example : $tree->remove($i);
189 Description : Remove an interval from the tree
190 Returntype : scalar, 1
if removal is successful, 0 otherwise
199 return 0 unless $self->root; # empty tree
201 my $node = $self->root->search_by_key($i->start);
202 return 0 unless $node;
204 my $node_intervals = $node->intervals;
205 if (scalar @{$node_intervals} > 1) {
206 # node with this key has more than this interval. Find it and remove
208 foreach my $j (0 .. $#{$node_intervals}) {
209 if ($node_intervals->[$j]->
start == $i->start and $node_intervals->[$j]->end == $i->end) {
210 splice @{$node_intervals}, $j, 1;
219 # update max of node and its ancestors, if necessary
220 if ($i->end == $node->max) {
221 my $node_highest_end = $node->_highest_end;
222 if ($node->left and $node->right) {
223 $node->{max} = max $node->left->max, $node->rigth->max, $node_highest_end;
224 } elsif ($node->left and not $node->right) {
225 $node->{max} = max $node->left->max, $node_highest_end;
226 } elsif ($node->right and not $node->left) {
227 $node->{max} = max $node->right->max, $node_highest_end;
229 $node->{max} = $node_highest_end;
232 $node->parent->_update_parents_max
if $node->parent;
241 } elsif (scalar @{$node_intervals}) {
242 # node with this key has only this interval
243 # check if the remaining node's interval is the one we want to remove
244 if ($node_intervals->[0]->start == $i->start and $node_intervals->[0]->end == $i->end) {
245 # remove the whole node from the tree
246 if ($node->key == $self->root->key) {
247 # we're removing the root node
248 # create dummy node temporarily taking root's parent node
252 $root_parent->left($self->root);
253 $self->root->parent($root_parent);
255 my $removed_node = $self->root->remove($node);
256 $self->root($root_parent->left);
258 $self->root->parent(undef)
if $self->root;
260 $removed_node = undef;
268 my $removed_node = $self->root->remove($node);
270 $removed_node = undef;
279 # the remaining record is not the one we want to remove
284 # no records at all in this node, shouldn't happen
285 croak
"This should not happen";
289 sub _in_order_traversal_delete {
290 my ($self, $node) = @_;
294 $self->_in_order_traversal_delete($node->left);
296 $self->_in_order_traversal_delete($node->right);
299 $node->parent(undef);
306 $self->_in_order_traversal_delete($self->root);