File Coverage

blib/lib/Tree/Treap.pm
Criterion Covered Total %
statement 9 185 4.8
branch 0 74 0.0
condition 0 36 0.0
subroutine 3 41 7.3
pod 12 28 42.8
total 24 364 6.5


line stmt bran cond sub pod time code
1             package Tree::Treap;
2 1     1   61 use 5.006;
  1         10  
  1         36  
3 1     1   4 use strict;
  1         1  
  1         22  
4 1     1   3 use warnings;
  1         1  
  1         1692  
5             our $VERSION = '0.02';
6              
7             my %comp = ( str => sub {return $_[0] cmp $_[1]},
8             rstr => sub {return $_[1] cmp $_[0]},
9             num => sub {return $_[0] <=> $_[1]},
10             rnum => sub {return $_[1] <=> $_[0]},
11             );
12              
13             sub new {
14 0     0 1   my $class = shift;
15 0   0       $class = ref($class)||$class;
16 0           my $self = bless {}, $class;
17 0   0       my $cmp = shift || "str";
18 0 0         if(ref($cmp) eq 'CODE'){
19 0           $self->{cmp} = $cmp;
20             } else {
21 0   0       $self->{cmp} = $comp{$cmp} || $comp{num};
22             }
23 0           $self->{priority} = -100;
24 0           $self->initialize(@_);
25 0           return $self;
26             }
27              
28 0     0 0   sub initialize {}
29              
30             sub insert {
31 0     0 1   my $self = shift;
32 0           my $key = shift;
33 0           my $data = shift;
34 0 0         $data = defined($data)? $data : $key;
35 0   0       my $priority = shift() || rand();
36            
37 0 0         if($self->_is_empty()) {
38 0           $self->{priority} = $priority,
39             $self->{key} = $key;
40 0           $self->{data} = $data;
41 0           $self->{left} = $self->new($self->{cmp});
42 0           $self->{right} = $self->new($self->{cmp});
43 0           return $self;
44             }
45            
46 0 0         if($self->gt($key)){
    0          
47 0           $self->{right}->insert($key,$data,$priority);
48 0 0         if($self->{right}->{priority} > $self->{priority}){
49 0           $self->_rotate_left();
50             }
51             }elsif($self->lt($key)){
52 0           $self->{left}->insert($key,$data,$priority);
53 0 0         if($self->{left}->{priority} > $self->{priority}){
54 0           $self->_rotate_right();
55             }
56              
57             }else{
58 0           $self->_delete_node();
59 0           $self->insert($key,$data,$priority);
60             }
61 0           return $self;
62             }
63              
64             sub delete {
65 0     0 1   my $self = shift;
66 0           my $key = shift;
67 0 0         return 0 unless $self = $self->_get_node($key);
68 0           $self->_delete_node();
69             }
70              
71              
72             sub _delete_node {
73 0     0     my $self = shift;
74 0 0         if($self->_is_leaf()) {
    0          
75 0           %$self = (priority => -100, cmp => $self->{cmp});
76             } elsif ($self->{left}->{priority} > $self->{right}->{priority}) {
77 0           $self->_rotate_right();
78 0           $self->{right}->_delete_node();
79             } else {
80 0           $self->_rotate_left();
81 0           $self->{left}->_delete_node();
82             }
83             }
84              
85              
86             sub keys {
87 0     0 1   my $self = shift;
88 0 0         return () if $self -> _is_empty ();
89 0           ($self->{left}->keys(), $self->{key}, $self->{right}->keys());
90             }
91              
92             sub keys_post {
93 0     0 0   my $self = shift;
94 0 0         return () if $self->_is_empty();
95 0           ($self->{left}->keys_post(), $self->{right}->keys_post(),$self->{key});
96             }
97              
98             sub keys_pre {
99 0     0 0   my $self = shift;
100 0 0         return () if $self->_is_empty();
101 0           ($self->{key},$self->{left}->keys_pre(), $self->{right}->keys_pre());
102             }
103              
104             sub values {
105 0     0 0   my $self = shift;
106 0 0         return () if $self->_is_empty ();
107 0           ($self->{left}->values(), $self->{data}, $self->{right}->values());
108             }
109              
110             sub exists {
111 0     0 1   my $self = shift;
112 0           my $key = shift;
113 0 0         return 1 if $self->_get_node($key);
114 0           return;
115             }
116              
117             sub get_val {
118 0     0 1   my $node = _get_node(@_);
119 0 0         return $node ? $node->{data} : undef;
120             }
121              
122              
123             sub _get_node {
124 0     0     my $self = shift;
125 0           my $key = shift;
126 0   0       while(!$self->_is_empty() and $self->ne($key)){
127 0 0         $self = $self->{$self->lt($key)?"left":"right"}
128             }
129 0 0         return $self->_is_empty() ? 0 : $self;
130             }
131              
132              
133             sub range_keys {
134 0     0 1   my $self = shift;
135 0           my @keys = map{$_->{key}} $self->_range_nodes(@_);
  0            
136 0           return @keys;
137             }
138             sub range_values {
139 0     0 1   my $self = shift;
140 0           my @values = map{$_->{data}} $self->_range_nodes(@_);
  0            
141 0           return @values;
142             }
143              
144             sub _range_nodes {
145 0     0     my $self = shift;
146 0           my $low = shift;
147 0           my $high = shift;
148 0           my @return;
149 0 0         return () if $self->_is_empty ();
150              
151 0 0 0       if (!defined $low || $self->lt($low)) {
152 0           push @return, $self->{left}->_range_nodes($low, $high);
153             }
154              
155 0 0 0       if ((!defined $low || $self->le($low)) &&
      0        
      0        
156             (!defined $high || $self->ge($high))) {
157 0           push @return, $self;
158             }
159              
160 0 0 0       if (!defined $high || $self->gt($high)) {
161 0           push @return, $self->{right}->_range_nodes($low, $high);
162             }
163              
164 0           @return;
165             }
166              
167              
168             sub split {
169 0     0 0   my $self = shift;
170 0           my $key = shift;
171 0           $self->insert($key,undef,100);
172 0           my($T1, $T2) = ($self->{left},$self->{right});
173 0           $self->delete($key);
174 0           return ($T1,$T2);
175             }
176              
177             sub join {
178 0     0 0   my $self = shift;
179 0           my $T1 = shift;
180 0           my $T2 = shift;
181 0 0         if($T1->{cmp}->($T1->maximum(),$T2->minimum())>=0){
182 0           warn "Tree1 must be less than Tree2 in join()";
183 0           return;
184             }
185 0           my $cat = $self->new($self->{cmp});
186 0           ($cat->{left}, $cat->{right}) = ($T1,$T2);
187 0           $cat->_delete_node();
188 0           return $cat;
189             }
190              
191              
192             sub minimum {
193 0     0 1   my $self = shift;
194 0 0         return if $self->_is_empty();
195 0           while ( not $self->{left}->_is_empty()){
196 0           $self = $self->{left};
197             }
198 0           return $self->{key};
199             }
200             sub maximum {
201 0     0 1   my $self = shift;
202 0 0         return if $self->_is_empty();
203 0           while ( not $self->{right}->_is_empty()){
204 0           $self = $self->{right};
205             }
206 0           return $self->{key};
207             }
208              
209              
210             sub as_string {
211 0     0 0   my $self = shift;
212 0   0       my $mult = shift || 1;
213 0           my $indent = " " x $mult;
214 0 0         return "$indent+\n" if $self -> _is_empty ();
215 0           return $self->{right}->as_string($mult + 2) .
216             "$indent+-$self->{key}\n" .
217             $self->{left}->as_string($mult + 2);
218             }
219              
220              
221             sub max_height {
222 0     0 0   my $self = shift;
223 0   0       my $depth = shift||0;
224 0 0         return $depth - 1 if $self->_is_empty();
225 0           my $left = $self->{left}->max_height($depth + 1);
226 0           my $right = $self->{right}->max_height($depth + 1);
227 0 0         $depth = $left if $left > $depth;
228 0 0         $depth = $right if $right > $depth;
229 0           return $depth;
230             }
231              
232             sub successor {
233 0     0 1   my $self = shift;
234 0           my $key = shift;
235 0           my $ret = $self->_successor($key)->{key};
236 0           $ret;
237             }
238             sub _successor {
239 0     0     my $self = shift;
240 0           my $key = shift;
241 0 0         return $self if $self->_is_empty();
242 0 0         return $self->{right}->_successor($key) if $self->ge($key);
243 0           my $succ;
244 0 0         $succ = $self->{left}->_successor($key) if $self->lt($key);
245 0 0         $succ->_is_empty()? $self : $succ;
246             }
247              
248             sub predecessor {
249 0     0 1   my $self = shift;
250 0           my $key = shift;
251 0           my $ret = $self->_predecessor($key)->{key};
252 0           $ret;
253             }
254             sub _predecessor {
255 0     0     my $self = shift;
256 0           my $key = shift;
257 0 0         return $self if $self->_is_empty ();
258 0 0         return $self->{left}->_predecessor($key) if $self->le($key);
259 0           my $pred;
260 0 0         $pred = $self->{right}->_predecessor ($key) if $self->gt($key);
261 0 0         $pred->_is_empty () ? $self : $pred;
262             }
263              
264              
265             sub CMP {
266 0     0 0   my $self = shift;
267 0           my $key = shift;
268 0           my $cmp = $self->{cmp};
269 0           $cmp->($key, $self->{key});
270             }
271              
272 0     0 0   sub lt {shift->CMP(@_) < 0;}
273 0     0 0   sub le {shift->CMP(@_) <= 0;}
274 0     0 0   sub eq {shift->CMP(@_) == 0;}
275 0     0 0   sub ne {shift->CMP(@_) != 0;}
276 0     0 0   sub ge {shift->CMP(@_) >= 0;}
277 0     0 0   sub gt {shift->CMP(@_) > 0;}
278 0     0 0   sub cmp {shift->CMP(@_)}
279              
280              
281             sub _clone_node {
282 0     0     my $self = shift;
283 0           my $other = shift;
284 0           %$self = %$other;
285             }
286              
287             sub _rotate_left {
288 0     0     my $self = shift;
289 0           my $tmp = $self->new($self->{cmp});
290 0           $tmp->_clone_node($self);
291 0           $self->_clone_node($self->{right});
292 0           $tmp->{right} = $self->{left};
293 0           $self->{left} = $tmp;
294            
295             }
296              
297             sub _rotate_right {
298 0     0     my $self = shift;
299 0           my $tmp = $self->new($self->{cmp});
300 0           $tmp->_clone_node($self);
301 0           $self->_clone_node($self->{left});
302 0           $tmp->{left} = $self->{right};
303 0           $self->{right} = $tmp;
304             }
305              
306              
307 0     0     sub _is_empty {!defined shift->{key}}
308              
309             sub _is_leaf {
310 0     0     my $self = shift;
311 0   0       return $self->{left}->_is_empty() &&
312             $self->{right}->_is_empty();
313             }
314              
315              
316              
317             1;
318             __END__