Mercurial > repos > jjohnson > crest
diff Tree/Interval/Node.pm @ 0:acc8d8bfeb9a
Uploaded
author | jjohnson |
---|---|
date | Wed, 08 Feb 2012 16:59:24 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Tree/Interval/Node.pm Wed Feb 08 16:59:24 2012 -0500 @@ -0,0 +1,208 @@ +package Tree::Interval::Node; + +use strict; +use Carp; +use Tree::Interval::Node::Constants; +use vars qw( $VERSION @EXPORT_OK ); + +require Exporter; +*import = \&Exporter::import; +@EXPORT_OK = qw[set_color color_of parent_of left_of right_of]; + +$VERSION = '0.1'; + +# key and interval is the same thing +my %attribute = ( + key => _KEY, + val => _VAL, + color => _COLOR, + parent => _PARENT, + left => _LEFT, + right => _RIGHT, + max => _MAX, + interval => _INTERVAL, +); + +#using an array instead of a hash for the node +sub _accessor { + my $index = shift; + return sub { + my $self = shift; + return undef unless $self; + if (@_) { + $self->[$index] = shift; + } + return $self->[$index]; + }; +} + +while(my($at, $idx) = each %attribute) { + no strict 'refs'; + *$at = _accessor($idx); +} + +sub new { + my $class = shift; + my $obj = []; + + if (@_) { + $obj->[_KEY] = $obj->[_INTERVAL] = shift; + $obj->[_VAL] = shift; + } + return bless $obj, $class; +} + +sub left_most { + my $self = shift; + while ($self->[_LEFT]) { + $self = $self->[_LEFT]; + } + return $self; +} + +sub right_most { + my $self = shift; + while ($self->[_RIGHT]) { + $self = $self->[_RIGHT]; + } + return $self; +} + +#find left_most leaf +sub leaf { + my $self = shift; + while (my $any_child = $self->[_LEFT] || $self->[_RIGHT]) { + $self = $any_child; + } + return $self; +} + +sub successor { + my $self = shift; + if ($self->[_RIGHT]) { + return $self->[_RIGHT]->left_most; + } + my $parent = $self->[_PARENT]; + while ($parent && $parent->[_RIGHT] && $self == $parent->[_RIGHT]) { + $self = $parent; + $parent = $parent->[_PARENT]; + } + return $parent; +} + +sub predecessor { + my $self = shift; + if ($self->[_LEFT]) { + return $self->[_LEFT]->right_most; + } + my $parent = $self->[_PARENT]; + while ($parent && $parent->[_LEFT] && $self == $parent->[_LEFT]) { + $self = $parent; + $parent = $parent->[_PARENT]; + } + return $parent; +} + +sub as_lol { + my $self = shift; + my $node = shift || $self; + my $aref; + push @$aref, + $node->[_LEFT] + ? $self->as_lol($node->[_LEFT]) + : '*'; + push @$aref, + $node->[_RIGHT] + ? $self->as_lol($node->[_RIGHT]) + : '*'; + my $color = ($node->[_COLOR] == RED ? 'R' : 'B'); + no warnings 'uninitialized'; + push @$aref, "$color:[$node->[_KEY][0],$node->[_KEY][1]]:$node->[_MAX]"; + return $aref; +} + +sub strip { + my $self = shift; + my $callback = shift; + + my $x = $self; + while($x) { + my $leaf = $x->leaf; + $x = $leaf->[_PARENT]; + + # detach $leaf from the (sub)tree + no warnings "uninitialized"; + if($leaf == $x->[_LEFT]) { + undef $x->[_LEFT]; + } + else { + undef $x->[_RIGHT]; + } + undef $leaf->[_PARENT]; + if($callback) { + $callback->($leaf); + } + + if(!$x->[_LEFT] && !$x->[_RIGHT]) { + $x = $x->[_PARENT]; + } + } +} + +sub DESTROY { $_[0]->strip; } + +# Null aware accessors to assist with rebalancings during insertion and deletion +# +# A weird case of Java to the rescue! +# These are inspired by http://www.javaresearch.org/source/jdk142/java/util/TreeMap.java.html +# which was found via http://en.wikipedia.org/wiki/Red-black_tree#Implementations + +# do wen need it? as we have accessors already +sub set_color { + my ($node, $color) = @_; + if($node) { + $node->[_COLOR] = $color; + } +} + +sub color_of { + $_[0] ? $_[0]->[_COLOR] : BLACK; +} + +sub parent_of { + $_[0] ? $_[0]->[_PARENT] : undef; +} + +sub left_of { + $_[0] ? $_[0]->[_LEFT] : undef; +} + +sub right_of { + $_[0] ? $_[0]->[_RIGHT] : undef; +} + +sub _overlap { + my ($a, $b) = @_; + return 1 if($a->[0] <= $b->[1] && $a->[1] >= $b->[0]); + return undef; +} + +sub intersect { + my $x = shift; + my $interval = shift; + return if(!$x); +# print $x->val->name, "\t", $x->key->[0], "\t", $x->key->[1], "\n"; + my @rtn; + if(_overlap($x->interval, $interval)) { + push @rtn, $x; + } +# my $y = $x->parent; + if($x->left && $x->left->max >= $interval->[0] ) { # && (!$y || _overlap($interval, [$y->interval->[0], $x->left->max]))) { + push @rtn, $x->left->intersect($interval); + } + push @rtn, $x->right->intersect($interval) if($x->right && _overlap($interval, [$x->interval->[0], $x->right->max])); + return @rtn; +} + +1; +