File Coverage

blib/lib/Tree/Bulk.pm
Criterion Covered Total %
statement 324 343 94.4
branch 216 296 72.9
condition 78 104 75.0
subroutine 57 59 96.6
pod 39 44 88.6
total 714 846 84.4


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -I/home/phil/perl/cpan/DataTableText/lib/ -I.
2             #-------------------------------------------------------------------------------
3             # Bulk Tree operations
4             # Philip R Brenan at appaapps dot com, Appa Apps Ltd Inc., 2021
5             #-------------------------------------------------------------------------------
6             # podDocumentation
7             package Tree::Bulk;
8             our $VERSION = "20210301";
9 1     1   822 use warnings FATAL => qw(all);
  1         7  
  1         39  
10 1     1   5 use strict;
  1         2  
  1         34  
11 1     1   5 use Carp qw(confess cluck);
  1         2  
  1         82  
12 1     1   529 use Data::Dump qw(dump);
  1         8034  
  1         62  
13 1     1   3841 use Data::Table::Text qw(:all);
  1         142746  
  1         1768  
14 1     1   15 use feature qw(say current_sub);
  1         2  
  1         6066  
15              
16             my $debug = 0; # Print debugging information if true
17              
18             sub saveLog($) #P Save a result to the log file if we are developing
19 0     0 0 0 {my ($string) = @_; # String to save
20 0         0 my $l = q(/home/phil/perl/z/bulkTree/zzz.txt); # Log file if available
21              
22 0 0       0 owf($l, $string) if -e $l;
23 0         0 confess "Saved to logfile:\n$l\n";
24             exit
25 0         0 }
26              
27             sub save # Simplified save
28 0     0 0 0 {my ($t) = @_; # Tree
29 0         0 saveLog($t->printKeys);
30             }
31              
32 74428     74428 0 422553 sub Left {q(left)} # Left
33 74370     74370 0 359867 sub Right {q(right)} # Right
34              
35             #D1 Bulk Tree # Bulk Tree
36              
37             sub node(;$$$$) #P Create a new bulk tree node
38 562     562 1 1736 {my ($key, $data, $up, $side) = @_; # Key, $data, parent node, side of parent node
39 562 100       9777 my $t = genHash(__PACKAGE__, # Bulk tree node
    100          
    100          
40             keysPerNode => $up ? $up->keysPerNode : 4, # Maximum number of keys per node
41             up => $up, # Parent node
42             left => undef, # Left node
43             right => undef, # Right node
44             height => 1, # Height of node
45             keys => [$key ? $key : ()], # Array of data items for this node
46             data => [$data ? $data : ()], # Data corresponding to each key
47             );
48              
49 562 100       63963 if ($up) # Install new node in tree
50 518 50       1325 {if ($side)
51 518         1316 {$up->{$side} = $t;
52 518         2173 $up->setHeights(2);
53             }
54             else
55 0 0       0 {confess 'Specify side' if !$side;
56             }
57             }
58             $t
59 562         13364 }
60              
61 14     14 1 46 sub new {node} # Create a new tree
62              
63             sub isRoot($) # Return the tree if it is the root
64 116664     116664 1 576534 {my ($tree) = @_; # Tree
65 116664 50       203770 confess unless $tree;
66 116664 100       1845568 !$tree->up ? $tree : undef
67             }
68              
69             sub root($) # Return the root node of a tree
70 1334     1334 1 3764 {my ($tree) = @_; # Tree
71 1334 50       4118 confess unless $tree;
72 1334         27911 for(; $tree->up; $tree = $tree->up) {}
73 1334         15602 $tree
74             }
75              
76             sub leaf($) # Return the tree if it is a leaf
77 93847     93847 1 373954 {my ($tree) = @_; # Tree
78 93847 50       169500 confess unless $tree;
79 93847 100 66     1562991 $tree and !$tree->right and !$tree->left ? $tree : undef
    100          
80             }
81              
82             sub duplex($) # Return the tree if it has left and right children
83 489     489 1 1168 {my ($tree) = @_; # Tree
84 489 50       1511 confess unless $tree;
85 489 100       8486 $tree->right and $tree->left ? $tree : undef
    100          
86             }
87              
88             sub simplex($) # Return the tree if it has either a left child or a right child but not both.
89 73696     73696 1 128535 {my ($tree) = @_; # Tree
90 73696 50       138092 confess unless $tree;
91 73696 100 100     1176473 $tree->right xor $tree->left ? $tree : undef
92             }
93              
94             sub simplexWithLeaf($) # Return the tree if it has either a left child or a right child but not both and the child it has a leaf.
95 9460     9460 1 229237 {my ($tree) = @_; # Tree
96 9460 50       22010 confess unless $tree;
97 9460 50 50     155314 return undef unless $tree->right xor $tree->left;
98 9460 100 100     342736 return undef if $tree->right and !$tree->right->leaf;
99 9429 100 100     270274 return undef if $tree->left and !$tree->left ->leaf;
100 9421         156416 $tree
101             }
102              
103             sub empty($) # Return the tree if it is empty
104 3442     3442 1 6131 {my ($tree) = @_; # Tree
105 3442 50       6799 confess unless $tree;
106 3442 100       7360 $tree->leaf and !$tree->keys->@* ? $tree : undef
    100          
107             }
108              
109             sub singleton($) # Return the tree if it contains only the root node and nothing else
110 4378     4378 1 7507 {my ($tree) = @_; # Tree
111 4378 50       7641 confess unless $tree;
112 4378 100       9274 $tree->leaf and $tree->isRoot ? $tree : undef;
    100          
113             }
114              
115             sub isLeftChild($) # Return the tree if it is the left child
116 726     726 1 2073 {my ($tree) = @_; # Tree
117 726 50       1675 confess unless $tree;
118 726 100 66     12114 $tree->up and $tree->up->left and $tree->up->left == $tree ? $tree : undef;
    100          
119             }
120              
121             sub isRightChild($) # Return the tree if it is the right child
122 170     170 1 425 {my ($tree) = @_; # Tree
123 170 50       372 confess unless $tree;
124 170 100 66     2855 $tree->up and $tree->up->right and $tree->up->right == $tree ? $tree : undef;
    100          
125             }
126              
127             sub name($) # Name of a tree
128 74474     74474 1 112386 {my ($tree) = @_; # Tree
129 74474 50       115351 confess unless $tree;
130 74474         1198786 join ' ', $tree->keys->@*
131             }
132              
133             sub names($) # Names of all nodes in a tree in order
134 3     3 1 10 {my ($tree) = @_; # Tree
135 3 50       11 confess unless $tree;
136 3         16 join ' ', map {$_->name} $tree->inorder;
  329         1929  
137             }
138              
139             sub setHeights($) #P Set heights along path to root
140 1011     1011 1 3795 {my ($tree) = @_; # Tree
141 1011 50       4040 confess unless $tree;
142 1011         3666 for(my $n = $tree; $n; $n = $n->up)
143 6257         33175 {$n->setHeight;
144 6257         29328 $n->balance;
145             }
146             } # setHeights
147              
148             sub actualHeight($) #P Get the height of a node
149 30182     30182 1 221532 {my ($tree) = @_; # Tree
150 30182 100       81717 return 0 unless $tree;
151 24288         375508 $tree->height
152             }
153              
154             sub maximum($$) #P Maximum of two numbers
155 7474     7474 1 13231 {my ($a, $b) = @_; # First, second
156 7474 100       122812 $a > $b ? $a : $b
157             }
158              
159             sub setHeight($) #P Set height of a tree from its left and right trees
160 7472     7472 1 15255 {my ($tree) = @_; # Tree
161 7472 50       13420 confess unless $tree;
162 7472         121306 my $l = actualHeight($tree->left);
163 7472         133118 my $r = actualHeight($tree->right);
164 7472         29223 $tree->height = 1 + maximum($l, $r);
165             } # setHeight
166              
167             =pod
168             Rotate left
169             p p
170             n r
171             l r n R
172             L R l L
173             =cut
174              
175             sub rotateLeft($) #P Rotate a node left
176 487     487 1 1112 {my ($n) = @_; # Node
177 487 50       1121 confess unless $n;
178 487         8272 my $p = $n->up;
179 487 100       2512 return unless $p;
180 169         2748 my $r = $n->right;
181 169 100       918 return unless $r;
182 168         2802 my $L = $r->left;
183 168 100       1308 $p->{$n->isRightChild ? Right : Left} = $r; $r->up = $p;
  168         2755  
184 168         3270 $r->left = $n; $n->up = $r;
  168         3124  
185 168 100       3098 $n->right = $L; $L->up = $n if $L;
  168         1671  
186 168         766 setHeight $_ for $n, $r, $p;
187 168         1192 $r->refill;
188             }
189              
190             sub rotateRight($) #P Rotate a node right
191 467     467 1 947 {my ($n) = @_; # Node
192 467 50       1054 confess unless $n;
193 467         7781 my $p = $n->up;
194 467 100       2537 return unless $p;
195 238         3774 my $l = $n->left;
196 238 100       1091 return unless $l;
197 237         3911 my $R = $l->right;
198 237 100       1358 $p->{$n->isLeftChild ? Left : Right} = $l; $l->up = $p;
  237         3810  
199 237         4367 $l->right = $n; $n->up = $l;
  237         4210  
200 237 100       4444 $n->left = $R; $R->up = $n if $R;
  237         2572  
201             # updateHeights $n;
202 237         977 setHeight $_ for $n, $l, $p;
203 237         1461 $l->refill;
204             }
205              
206             =pod
207             Balance - make the deepest sub tree one less deep
208             1 1
209             2 5
210             6 2 6
211             5 4
212             4 3
213             3
214             =cut
215              
216             sub balance($) # Balance a node
217 6751     6751 1 12172 {my ($t) = @_; # Tree
218 6751 50       13130 confess unless $t;
219             #check($t);
220 6751         106092 my ($l, $r) = (actualHeight($t->left), actualHeight($t->right));
221              
222 6751 100       34366 if ($l > 2 * $r + 1) # Rotate right
    100          
223 425 50       6942 {if (my $l = $t->left) # Counter balance if necessary
224 425 100       8163 {if (actualHeight($l->right) > actualHeight($l->left))
225 48         219 {$l->rotateLeft
226             }
227             }
228 425         4011 $t->rotateRight;
229             }
230             elsif ($r > 2 * $l + 1) # Rotate left
231 437 50       7268 {if (my $r = $t->right) # Counter balance if necessary
232 437 100       8467 {if (actualHeight($r->left) > actualHeight($r->right))
233 40         195 {$r->rotateRight
234             }
235             }
236 437         3823 $t->rotateLeft;
237             }
238             #check($t);
239              
240             $t
241 6751         109296 } # balance
242              
243             sub insertUnchecked($$$) #P Insert a key and some data into a tree
244             {my ($tree, $key, $data) = @_; # Tree, key, data
245             confess unless $tree;
246             confess unless defined $key;
247              
248             my sub insertIntoNode # Insert the current key into the specified node
249             {my @k; my @d; # Rebuilt node
250             my $low = 1; # Keys less than the key
251             for my $i(keys $tree->keys->@*) # Insert key and data in node
252             {my $k = $tree->keys->[$i];
253             confess "Duplicate key" if $k == $key;
254             if ($low and $k > $key) # Insert key and data before first greater key
255             {$low = undef;
256             push @k, $key;
257             push @d, $data;
258             }
259             push @k, $k;
260             push @d, $tree->data->[$i];
261             }
262             if ($low) # Key bigger than largest key
263             {push @d, $data;
264             push @k, $key;
265             }
266             $tree->keys = \@k; $tree->data = \@d; # Keys and data in node
267             } # insertIntoNode
268              
269             if ($tree->keys->@* < $tree->keysPerNode and leaf $tree) # Small node so we can add within the node
270             {insertIntoNode;
271             return $tree;
272             }
273              
274             elsif ($key < $tree->keys->[0]) # Less than least - Go left
275             {if ($tree->left) # New node left
276             {return __SUB__->($tree->left, $key, $data);
277             }
278             else
279             {return node $key, $data, $tree, Left; # Add a new node left
280             }
281             }
282              
283             elsif ($key > $tree->keys->[-1]) # Greater than most - go right
284             {if ($tree->right) # New node right
285             {return __SUB__->($tree->right, $key, $data);
286             }
287             else
288             {return node $key, $data, $tree, Right; # Add a new node right
289             }
290             }
291              
292             else # Full node and key is inside it
293             {insertIntoNode; # Keys in node
294             if ($tree->keys->@* > $tree->keysPerNode) # Reinsert last key and data if the node is now to big
295             {my $k = pop $tree->keys->@*;
296             my $d = pop $tree->data->@*;
297             if (my $r = $tree->right)
298             {return $r->insertUnchecked($k, $d);
299             }
300             else # Insert right in new node and balance
301             {return node $k, $d, $tree, Right;
302             }
303             }
304             return $tree;
305             }
306             } # insertUnchecked
307              
308             sub insert($$$) # Insert a key and some data into a tree
309 1234     1234 1 3147 {my ($tree, $key, $data) = @_; # Tree, key, data
310 1234 50       2857 confess unless $tree;
311 1234 50       2700 confess unless defined $key;
312 1234         8950 $tree->insertUnchecked($key, $data);
313             } # insert
314              
315             sub find($$) # Find a key in a tree and returns its data
316 97922     97922 1 177986 {my ($tree, $key) = @_; # Tree, key
317 97922 50       178289 confess unless $tree;
318 97922 50       158588 confess "No key" unless defined $key;
319 97922 50       259761 confess "Non numeric key" unless $key =~ m(\A\d+\Z);
320              
321             sub # Find the key in the sub-tree
322 515873     515873   2539065 {my ($tree) = @_; # Sub-tree
323 515873 100       917353 if ($tree)
324 515871         8474323 {my $keys = $tree->keys;
325 515871 50       2353235 confess "Empty node" unless $keys->@*;
326              
327 515871 100       3908841 return __SUB__->($tree->left) if $key < $$keys[ 0];
328 323276 100       3916830 return __SUB__->($tree->right) if $key > $$keys[-1];
329              
330 97920         201611 for my $i(keys $keys->@*) # Find key in node
331 237672         3764629 {my $v = $tree->data->[$i];
332 237672 50       1051112 confess "undefined data for key $key" unless defined $v;
333 237672 100       1875427 return $tree->data->[$i] if $key == $$keys[$i];
334             }
335             }
336             undef
337 97922         443950 }->($tree)
  2         13  
338             } # find
339              
340             sub first($) # First node in a tree
341 356     356 1 8549 {my ($n) = @_; # Tree
342 356 50       1079 confess unless $n;
343 356         6733 $n = $n->left while $n->left;
344 356         7512 $n
345             }
346              
347             sub last($) # Last node in a tree
348 412     412 1 9558 {my ($n) = @_; # Tree
349 412 50       1079 confess unless $n;
350 412         6586 $n = $n->right while $n->right;
351 412         10355 $n
352             }
353              
354             sub next($) # Next node in order
355 1079     1079 1 2566 {my ($tree) = @_; # Tree
356 1079 50       2542 confess unless $tree;
357 1079 100       17862 if (my $r = $tree->right)
358 830 100       16984 {return $r->left ? $r->left->first : $r;
359             }
360 249         1057 my $p = $tree;
361 249         450 for(; $p; $p = $p->up)
362 489 100 100     27921 {return $p->up unless $p->up and $p->up->right and $p->up->right == $p;
      100        
363             }
364             undef
365 0         0 }
366              
367             sub prev($) # Previous node in order
368 827     827 1 1971 {my ($tree) = @_; # Tree
369 827 50       1629 confess unless $tree;
370 827 100       13646 if (my $l = $tree->left)
371 800 100       16003 {return $l->right ? $l->right->last : $l;
372             }
373 27         109 my $p = $tree;
374 27         52 for(; $p; $p = $p->up)
375 55 100 66     3209 {return $p->up unless $p->up and $p->up->left and $p->up->left == $p;
      100        
376             }
377             undef
378 0         0 }
379              
380             sub inorder($) # Return a list of all the nodes in a tree in order
381 8     8 1 25 {my ($tree) = @_; # Tree
382 8 50       24 confess unless $tree;
383 8         34 my @n;
384 8         34 for(my $n = $tree->first; $n; $n = $n->next)
385 434         18729 {push @n, $n;
386             }
387             @n
388 8         232 }
389              
390             sub unchain($) #P Remove a tree from the middle of a chain. A leaf is considered to be in the middle of a chain and so can be removed with this method
391 487     487 1 18622 {my ($t) = @_; # Tree
392 487 50       1179 confess unless $t;
393 487 50       1744 confess "Duplex tree cannot be unchained" if duplex $t;
394 487 50       10301 confess "Root cannot be unchained" unless my $p = $t->up;
395              
396 487   66     9889 my $c = $t->left // $t->right; # Not duplex so at most one of these
397 487 100       12539 $p->{$t->isLeftChild ? Left : Right} = $c; # Unchain
398 487 100       1235 $c->up = $p if $c;
399 487         8260 $t->up = undef; #need to keep yhis so balance can continue up the tree # Free the middle link
400              
401 487 100       9148 if (my $l = $p->left) {$l->setHeights($l->height)} # Set heights from a known point
  129 100       2591  
402 129         5042 elsif (my $r = $p->right) {$r->setHeights($r->height)}
403 229         6026 else {$p->setHeights(1)}
404              
405 487         3589 $p->balance; # Rebalance parent
406              
407 487         1699 $p # Unchained node
408             } # unchain
409              
410             sub refillFromRight($) #P Push a key to the target node from the next node
411 590     590 1 5428 {my ($target) = @_; # Target tree
412              
413 590 50       1776 confess unless $target;
414 590 50       9722 confess "No right" unless $target->right; # Ensure source will be in this sub tree
415 590 50       5192 confess "No source" unless my $source = $target->next; # No source
416              
417 590   100     12682 while ($source->keys->@* > 0 and $target->keys->@* < $target->keysPerNode) # Transfer fill from source
418 595         34021 {push $target->keys->@*, shift $source->keys->@*;
419 595         13652 push $target->data->@*, shift $source->data->@*;
420             }
421 590 100       28039 $source->unchain if $source->empty;
422 590         16998 $_->refill for $target, $source;
423             } # refillFromRight
424              
425             sub refillFromLeft($) #P Push a key to the target node from the previous node
426 772     772 1 5443 {my ($target) = @_; # Target tree
427              
428 772 50       1685 confess unless $target;
429 772 50       12286 confess "No left" unless $target->left; # Ensure source will be in this sub tree
430 772 50       5111 confess "No source" unless my $source = $target->prev; # No source
431              
432 772   100     14969 while ($source->keys->@* > 0 and $target->keys->@* < $target->keysPerNode) # Transfer fill from source
433 418         22582 {unshift $target->keys->@*, pop $source->keys->@*;
434 418         9500 unshift $target->data->@*, pop $source->data->@*;
435             }
436              
437 772 100       36753 $source->unchain if $source->empty;
438 772         28704 $_->refill for $target, $source;
439             } # refillFromLeft
440              
441             sub refill($) #P Refill a node so it has the expected number of keys
442 4377     4377 1 36498 {my ($tree) = @_; # Tree
443 4377 50       9981 confess unless $tree;
444 4377 100       11374 return if $tree->singleton;
445 3984 100       104335 return if $tree->keys->@* == $tree->keysPerNode;
446              
447 2074 100       47770 if ($tree->empty) # Remove an empty leaf that is not the root
    100          
448 171 50       7733 {$tree->unchain unless $tree->isRoot;
449             }
450              
451             elsif ($tree->keys->@* < $tree->keysPerNode) # Refill the node from neighboring leaf nodes
452 1886 100       118252 {if (!$tree->leaf) # Do not refill leaves
453 982 100       27796 {$tree->refillFromRight if $tree->right;
454 982 100       26643 $tree->refillFromLeft if $tree->left;
455             }
456             }
457              
458             else
459 17         1095 {while($tree->keys->@* > $tree->keysPerNode) # Empty node if over full
460 25         967 {$tree->insertUnchecked(pop $tree->keys->@*, pop $tree->data->@*); # Reinsert lower down
461             }
462             }
463             } # refill
464              
465             sub delete($$) # Delete a key in a tree
466 1167     1167 1 3397 {my ($tree, $key) = @_; # Tree, key
467 1167 50       4079 confess unless $tree;
468 1167 50       2860 confess "No key" unless defined $key;
469              
470             sub # Find then delete the key in the sub-tree
471 4661     4661   27079 {my ($tree) = @_; # Sub-tree
472 4661 50       9878 return unless $tree;
473 4661 50       78634 return unless $tree->keys->@*; # Empty tree
474 4661 100       90361 if ($key < $tree->keys->[ 0]) {__SUB__->($tree->left)} # Less than least key so go left
  1653 100       33184  
    50          
475 1841         71309 elsif ($key > $tree->keys->[-1]) {__SUB__->($tree->right)} # Greater than most key so go right
476 4201         55893 elsif (grep {$_ == $key} $tree->keys->@*) # Key present in current node
477 1167         2777 {my @k, my @d;
478 1167         19879 for my $i(keys $tree->keys->@*) # Remove the key and corresponding data
479 4201 100       81626 {next if $tree->keys->[$i] == $key;
480 3034         59304 push @d, $tree->data->[$i];
481 3034         58195 push @k, $tree->keys->[$i];
482             }
483 1167         24327 $tree->keys = \@k; $tree->data = \@d;
  1167         23913  
484 1167         9101 $tree->refill; # Refill the tree
485             }
486 1167         9991 }->($tree);
487             } # delete
488              
489             sub printKeys2($$$) #P print the keys for a tree
490 522     522 1 2203 {my ($t, $in, $g) = @_; # Tree, indentation, list of keys,
491 522 100       1046 return unless $t;
492 243         3841 __SUB__->($t->left, $in+1, $g); # Left
493              
494 243         4124 my $h = $t->height;
495 243 100 100     4253 my $s = $t->up && $t->up->left && $t->up->left == $t ? 'L' : # Print
    100 66        
496             $t->up && $t->up->right && $t->up->right == $t ? 'R' : 'S';
497 243 100 100     24119 $s .= $t->leaf ? 'z' : $t->isRoot ? 'A' : $t->left && $t->right ? 'd' : $t->left ? 'l' : 'r';
    100          
    100          
    100          
498 243         7224 $s .= "$in $h ".(' ' x $in);
499 243         554 $s .= $t->name;
500 243 100       4800 $s .= '->'.$t->up->name if $t->up;
501 243         1364 push @$g, $s;
502              
503 243         4251 __SUB__->($t->right, $in+1, $g); # Right
504             }
505              
506             sub printKeys($) # Print the keys in a tree
507 36     36 1 68 {my ($t) = @_; # Tree
508 36 50       72 confess unless $t;
509              
510 36         56 my @s;
511 36         139 printKeys2 $t, 0, \@s;
512              
513 36         915 (join "\n", @s, "") =~ s(\s+\Z) (\n)sr
514             } # printKeys
515              
516             sub setKeysPerNode($$) # Set the number of keys for the current node
517 81     81 1 151 {my ($tree, $N) = @_; # Tree, keys per node to be set
518 81 50       156 confess unless $tree;
519 81 50 33     266 confess unless $N and $N > 0;
520 81         1915 $tree->keysPerNode = $N; # Set
521 81         405 $tree->refill; # Refill if necessary
522 81         899 $tree # Allow chaining
523             } # setKeysPerNode
524              
525             sub printKeysAndData($) # Print the mapping from keys to data in a tree
526             {my ($t) = @_; # Tree
527             confess unless $t;
528             my @s;
529             my sub print($$)
530             {my ($t, $in) = @_;
531             return unless $t;
532             __SUB__->($t->left, $in+1); # Left
533             push @s, [$t->keys->[$_], $t->data->[$_]] for keys $t->keys->@*; # Find key in node
534             __SUB__->($t->right, $in+1); # Right
535             }
536             print $t, 0;
537             formatTableBasic(\@s)
538             } # printKeysAndData
539              
540             sub checkLRU($) #P Confirm pointers in tree
541 1332     1332 1 3417 {my ($tree) = @_; # Tree
542 1332         2242 my %seen; # Nodes we have already seen
543              
544             sub # Check pointers in a tree
545 148720     148720   250767 {my ($tree, $dir) = @_; # Tree
546 148720 100       295005 return unless $tree;
547              
548 73694 50       131856 confess "Recursed $dir into: ".$tree->name if $seen{$tree->name}++;
549              
550 73694         1627069 __SUB__->($tree->left, Left);
551 73694         1182938 __SUB__->($tree->right, Right);
552 1332         5242 }->($tree->root);
553             }
554              
555             sub check($) #P Confirm that each node in a tree is ordered correctly
556 1332     1332 1 3585 {my ($tree) = @_; # Tree
557 1332 50       4166 confess unless $tree;
558 1332         5395 $tree->checkLRU;
559              
560 1332         25284 my $maxHeight = 0;
561              
562             sub
563 148720     148720   727718 {my ($tree) = @_; # Tree
564 148720 100       279902 return unless $tree;
565              
566 73694         1155326 __SUB__->($tree->left);
567 73694         1219147 __SUB__->($tree->right);
568              
569 73694 50       1222743 confess $tree->name unless $tree->keys->@* == $tree->data->@*; # Check key count matches data count
570              
571 73694 50 100     1652366 if ( !$tree->leaf and !$tree->isRoot # Confirm that all interior nodes are fully filled
      66        
572             and $tree->keys->@* != $tree->keysPerNode)
573 0         0 {confess "Interior node not full: "
574             .$tree->name."\n". $tree->root->printKeys;
575             }
576              
577 73694 50 66     2517909 confess $tree->name unless $tree->isRoot or # Node is either a root or a left or right child
      100        
      100        
      33        
      33        
      66        
578             $tree->up && $tree->up->left && $tree == $tree->up->left or
579             $tree->up && $tree->up->right && $tree == $tree->up->right;
580              
581 73694 50 33     10350007 confess 'Left:'.$tree->name if $tree->left and # Left child has correct parent
      66        
582             !$tree->left->up || $tree->left->up != $tree;
583              
584 73694 50 33     3764635 confess 'Right:'.$tree->name if $tree->right and # Right child has correct parent
      66        
585             !$tree->right->up || $tree->right->up != $tree;
586              
587 73694 50 100     2732484 if ($tree->simplex and !$tree->simplexWithLeaf and $tree->up # Simplex children must always have duplex parents
      100        
      66        
      33        
588             and !$tree->up->isRoot and !$tree->up->duplex)
589 0         0 {confess "Simplex does not have duplex parent: ".$tree->name
590             ."\n".$tree->root->printKeys;
591             }
592              
593 73694 100       2568851 $maxHeight = $tree->height if $tree->height > $maxHeight;
594              
595 73694         1578073 my @k = $tree->keys->@*; # Check keys
596 73694 50       1528258 @k <= $tree->keysPerNode or confess "Too many keys:".scalar(@k);
597 73694         423985 for my $i(keys @k)
598 147852 50       289684 {confess "undef key position $i" unless defined $k[$i];
599             }
600              
601 73694         1236533 my @d = $tree->data->@*; # Check data
602 73694 50       1442988 @d <= $tree->keysPerNode or confess "Too many data:".scalar(@d);
603              
604 73694         330990 my %k;
605 73694         234583 for my $i(1..$#k)
606 74161 50       146819 {confess "Out of order: ", dump(\@k) if $k[$i-1] >= $k[$i];
607 74161 50       175564 confess "Duplicate key: ", $k[$i] if $k{$k[$i]}++;
608 74161 50       175724 confess "Undefined data: ", $k[$i] unless defined $d[$i];
609             }
610 1332         12853 }->($tree);
611              
612 1332 50       87472 if ($tree->height < $maxHeight)
613 0         0 {say STDERR "AAAA height failure", $tree->name;
614 0         0 save($tree);
615             }
616             } # check
617              
618             sub checkAgainstHash($%) #P Check a tree against a hash
619 908     908 1 26345 {my ($t, %t) = @_; # Tree, expected
620              
621 908         12524 for my $k(keys %t) # Check we can find all the keys expected
622 97914         230272 {my ($t) = @_;
623 97914         164541 my $v = $t{$k};
624 97914 50       170189 confess "Cannot find $k" unless my $f = find($t, $k);
625 97914 50       1173012 confess "Found $f but expected $v" unless $f == $v;
626             }
627              
628             sub # Check that the tree does not contain unexpected keys
629 88474     88474   376203 {my ($t) = @_;
630 88474 100       169991 return unless $t;
631              
632 43783         678740 __SUB__->($t->left); # Left
633 43783         694937 for($t->keys->@*)
634 97914 50       353226 {confess $_ unless delete $t{$_};
635             }
636 43783         695416 __SUB__->($t->right); # Right
637 908         16404 }->($t);
638              
639 908 50       13300 confess if keys %t; # They should have all been deleted
640             } # checkAgainstHash
641             #d
642             #-------------------------------------------------------------------------------
643             # Export - eeee
644             #-------------------------------------------------------------------------------
645              
646 1     1   9 use Exporter qw(import);
  1         3  
  1         47  
647              
648 1     1   7 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         2  
  1         494  
649              
650             @ISA = qw(Exporter);
651             @EXPORT = qw();
652             @EXPORT_OK = qw(
653             );
654             %EXPORT_TAGS = (all=>[@EXPORT, @EXPORT_OK]);
655              
656             # podDocumentation
657             =pod
658              
659             =encoding utf-8
660              
661             =head1 Name
662              
663             Tree::Bulk - Bulk Tree operations
664              
665             =head1 Synopsis
666              
667             Bulk trees store several (key,data) pairs in each node of a balanced tree to
668             reduce the number of tree pointers: up, left, right, etc. used to maintain the
669             tree. This has no useful effect in Perl code, but in C code, especially C code
670             that uses SIMD instructions, the savings in space can be considerable which
671             allows the processor caches to be used more effectively. This module
672             demonstrates insert, find, delete operations on bulk trees as a basis for
673             coding these algorithms more efficiently in assembler code.
674              
675             is_deeply $t->printKeys, <
676             SA0 4 1 2 3 4
677             Lz2 1 5 6 7 8->9 10 11 12
678             Rd1 3 9 10 11 12->1 2 3 4
679             Lz3 1 13 14 15 16->17 18 19 20
680             Rd2 2 17 18 19 20->9 10 11 12
681             Rz3 1 21 22->17 18 19 20
682             END
683              
684             for my $n($t->inorder)
685             {$n->setKeysPerNode(2);
686             }
687              
688             is_deeply $t->printKeys, <
689             SA0 5 1 2
690             Lz3 1 3 4->5 6
691             Ld2 2 5 6->9 10
692             Rz3 1 7 8->5 6
693             Rd1 4 9 10->1 2
694             Lz4 1 11 12->13 14
695             Ld3 2 13 14->17 18
696             Rz4 1 15 16->13 14
697             Rd2 3 17 18->9 10
698             Rr3 2 19 20->17 18
699             Rz4 1 21 22->19 20
700             END
701              
702             =head1 Description
703              
704             Bulk Tree operations
705              
706              
707             Version "20210226".
708              
709              
710             The following sections describe the methods in each functional area of this
711             module. For an alphabetic listing of all methods by name see L.
712              
713              
714              
715             =head1 Bulk Tree
716              
717             Bulk Tree
718              
719             =head2 isRoot($tree)
720              
721             Return the tree if it is the root
722              
723             Parameter Description
724             1 $tree Tree
725              
726             B
727              
728              
729             if (1)
730             {lll "Attributes";
731             my $t = Tree::Bulk::new->setKeysPerNode(1);
732             my $b = $t->insert(2,4);
733             my $a = $t->insert(1,2);
734             my $c = $t->insert(3,6);
735             ok $a->isLeftChild;
736             ok $c->isRightChild;
737             ok !$a->isRightChild;
738             ok !$c->isLeftChild;
739              
740             ok $b->isRoot; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
741              
742              
743             ok !$a->isRoot; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
744              
745              
746             ok !$c->isRoot; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
747              
748             ok $a->leaf;
749             ok $c->leaf;
750             ok $b->duplex;
751             ok $c->root == $b;
752             ok $c->root != $a;
753             }
754              
755              
756             =head2 root($tree)
757              
758             Return the root node of a tree
759              
760             Parameter Description
761             1 $tree Tree
762              
763             B
764              
765              
766             if (1)
767             {lll "Attributes";
768             my $t = Tree::Bulk::new->setKeysPerNode(1);
769             my $b = $t->insert(2,4);
770             my $a = $t->insert(1,2);
771             my $c = $t->insert(3,6);
772             ok $a->isLeftChild;
773             ok $c->isRightChild;
774             ok !$a->isRightChild;
775             ok !$c->isLeftChild;
776             ok $b->isRoot;
777             ok !$a->isRoot;
778             ok !$c->isRoot;
779             ok $a->leaf;
780             ok $c->leaf;
781             ok $b->duplex;
782              
783             ok $c->root == $b; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
784              
785              
786             ok $c->root != $a; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
787              
788             }
789              
790              
791             =head2 leaf($tree)
792              
793             Return the tree if it is a leaf
794              
795             Parameter Description
796             1 $tree Tree
797              
798             B
799              
800              
801             if (1)
802             {lll "Attributes";
803             my $t = Tree::Bulk::new->setKeysPerNode(1);
804             my $b = $t->insert(2,4);
805             my $a = $t->insert(1,2);
806             my $c = $t->insert(3,6);
807             ok $a->isLeftChild;
808             ok $c->isRightChild;
809             ok !$a->isRightChild;
810             ok !$c->isLeftChild;
811             ok $b->isRoot;
812             ok !$a->isRoot;
813             ok !$c->isRoot;
814              
815             ok $a->leaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
816              
817              
818             ok $c->leaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
819              
820             ok $b->duplex;
821             ok $c->root == $b;
822             ok $c->root != $a;
823             }
824              
825              
826             =head2 duplex($tree)
827              
828             Return the tree if it has left and right children
829              
830             Parameter Description
831             1 $tree Tree
832              
833             B
834              
835              
836             if (1)
837             {lll "Attributes";
838             my $t = Tree::Bulk::new->setKeysPerNode(1);
839             my $b = $t->insert(2,4);
840             my $a = $t->insert(1,2);
841             my $c = $t->insert(3,6);
842             ok $a->isLeftChild;
843             ok $c->isRightChild;
844             ok !$a->isRightChild;
845             ok !$c->isLeftChild;
846             ok $b->isRoot;
847             ok !$a->isRoot;
848             ok !$c->isRoot;
849             ok $a->leaf;
850             ok $c->leaf;
851              
852             ok $b->duplex; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
853              
854             ok $c->root == $b;
855             ok $c->root != $a;
856             }
857              
858              
859             =head2 simplex($tree)
860              
861             Return the tree if it has either a left child or a right child but not both.
862              
863             Parameter Description
864             1 $tree Tree
865              
866             B
867              
868              
869             if (1)
870             {lll "SetHeights";
871             my $a = node(1,1)->setKeysPerNode(1);
872             my $b = node(2,2)->setKeysPerNode(1);
873             my $c = node(3,3)->setKeysPerNode(1);
874             my $d = node(4,4)->setKeysPerNode(1);
875             my $e = node(5,5);
876             $a->right = $b; $b->up = $a;
877             $b->right = $c; $c->up = $b;
878             $c->right = $d; $d->up = $c;
879             $d->right = $e; $e->up = $d;
880              
881             is_deeply $a->printKeys, <
882             SA0 1 1
883             Rr1 1 2->1
884             Rr2 1 3->2
885             Rr3 1 4->3
886             Rz4 1 5->4
887             END
888             #save $a;
889              
890             $e->setHeights(1);
891             is_deeply $a->printKeys, <
892             SA0 4 1
893             Rr1 3 2->1
894             Lz3 1 3->4
895             Rd2 2 4->2
896             Rz3 1 5->4
897             END
898             #save $a;
899              
900             ok $b->simplex; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
901              
902              
903             ok !$c->simplex; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
904              
905              
906             $c->balance;
907             is_deeply $a->printKeys, <
908             SA0 4 1
909             Rr1 3 2->1
910             Lz3 1 3->4
911             Rd2 2 4->2
912             Rz3 1 5->4
913             END
914             #save $a;
915              
916             $b->balance;
917             is_deeply $a->printKeys, <
918             SA0 4 1
919             Lr2 2 2->4
920             Rz3 1 3->2
921             Rd1 3 4->1
922             Rz2 1 5->4
923             END
924             #save $a;
925             }
926              
927              
928             =head2 simplexWithLeaf($tree)
929              
930             Return the tree if it has either a left child or a right child but not both and the child it has a leaf.
931              
932             Parameter Description
933             1 $tree Tree
934              
935             B
936              
937              
938             if (1)
939             {lll "Balance";
940             my $a = node(1,1)->setKeysPerNode(1); $a->height = 5;
941             my $b = node(2,2)->setKeysPerNode(1); $b->height = 4;
942             my $c = node(3,3)->setKeysPerNode(1); $c->height = 3;
943             my $d = node(4,4)->setKeysPerNode(1); $d->height = 2;
944             my $e = node(5,5); $e->height = 1;
945             $a->right = $b; $b->up = $a;
946             $b->right = $c; $c->up = $b;
947             $c->right = $d; $d->up = $c;
948             $d->right = $e; $e->up = $d;
949              
950             $e->balance;
951             is_deeply $a->printKeys, <
952             SA0 5 1
953             Rr1 4 2->1
954             Rr2 3 3->2
955             Rr3 2 4->3
956             Rz4 1 5->4
957             END
958             #save $a;
959              
960             ok $d->simplexWithLeaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
961              
962              
963             ok !$c->simplexWithLeaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
964              
965              
966             $d->balance;
967             is_deeply $a->printKeys, <
968             SA0 5 1
969             Rr1 4 2->1
970             Rr2 3 3->2
971             Rr3 2 4->3
972             Rz4 1 5->4
973             END
974             #save $a;
975              
976             $c->balance;
977             is_deeply $a->printKeys, <
978             SA0 5 1
979             Rr1 3 2->1
980             Lz3 1 3->4
981             Rd2 2 4->2
982             Rz3 1 5->4
983             END
984             #save $a;
985              
986             $b->balance;
987             is_deeply $a->printKeys, <
988             SA0 4 1
989             Lr2 2 2->4
990             Rz3 1 3->2
991             Rd1 3 4->1
992             Rz2 1 5->4
993             END
994             #save $a;
995             }
996              
997              
998             =head2 empty($tree)
999              
1000             Return the tree if it is empty
1001              
1002             Parameter Description
1003             1 $tree Tree
1004              
1005             B
1006              
1007              
1008             if (1)
1009             {lll "Balance";
1010             my $t = Tree::Bulk::new->setKeysPerNode(1);
1011              
1012             ok $t->empty; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1013              
1014             ok $t->singleton;
1015             }
1016              
1017              
1018             =head2 singleton($tree)
1019              
1020             Return the tree if it contains only the root node and nothing else
1021              
1022             Parameter Description
1023             1 $tree Tree
1024              
1025             B
1026              
1027              
1028             if (1)
1029             {lll "Balance";
1030             my $t = Tree::Bulk::new->setKeysPerNode(1);
1031             ok $t->empty;
1032              
1033             ok $t->singleton; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1034              
1035             }
1036              
1037              
1038             =head2 isLeftChild($tree)
1039              
1040             Return the tree if it is the left child
1041              
1042             Parameter Description
1043             1 $tree Tree
1044              
1045             B
1046              
1047              
1048             if (1)
1049             {lll "Attributes";
1050             my $t = Tree::Bulk::new->setKeysPerNode(1);
1051             my $b = $t->insert(2,4);
1052             my $a = $t->insert(1,2);
1053             my $c = $t->insert(3,6);
1054              
1055             ok $a->isLeftChild; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1056              
1057             ok $c->isRightChild;
1058             ok !$a->isRightChild;
1059              
1060             ok !$c->isLeftChild; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1061              
1062             ok $b->isRoot;
1063             ok !$a->isRoot;
1064             ok !$c->isRoot;
1065             ok $a->leaf;
1066             ok $c->leaf;
1067             ok $b->duplex;
1068             ok $c->root == $b;
1069             ok $c->root != $a;
1070             }
1071              
1072              
1073             =head2 isRightChild($tree)
1074              
1075             Return the tree if it is the right child
1076              
1077             Parameter Description
1078             1 $tree Tree
1079              
1080             B
1081              
1082              
1083             if (1)
1084             {lll "Attributes";
1085             my $t = Tree::Bulk::new->setKeysPerNode(1);
1086             my $b = $t->insert(2,4);
1087             my $a = $t->insert(1,2);
1088             my $c = $t->insert(3,6);
1089             ok $a->isLeftChild;
1090              
1091             ok $c->isRightChild; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1092              
1093              
1094             ok !$a->isRightChild; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1095              
1096             ok !$c->isLeftChild;
1097             ok $b->isRoot;
1098             ok !$a->isRoot;
1099             ok !$c->isRoot;
1100             ok $a->leaf;
1101             ok $c->leaf;
1102             ok $b->duplex;
1103             ok $c->root == $b;
1104             ok $c->root != $a;
1105             }
1106              
1107              
1108             =head2 name($tree)
1109              
1110             Name of a tree
1111              
1112             Parameter Description
1113             1 $tree Tree
1114              
1115             B
1116              
1117              
1118             if (1)
1119             {lll "Split and Refill";
1120             my $N = 22;
1121             my $t = Tree::Bulk::new;
1122             for my $k(1..$N)
1123             {$t->insert($k, 2 * $k);
1124             }
1125              
1126              
1127             is_deeply $t->name, "1 2 3 4"; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1128              
1129              
1130             is_deeply $t->printKeys, <
1131             SA0 4 1 2 3 4
1132             Lz2 1 5 6 7 8->9 10 11 12
1133             Rd1 3 9 10 11 12->1 2 3 4
1134             Lz3 1 13 14 15 16->17 18 19 20
1135             Rd2 2 17 18 19 20->9 10 11 12
1136             Rz3 1 21 22->17 18 19 20
1137             END
1138             #save $t;
1139              
1140             for my $n($t->inorder)
1141             {$n->setKeysPerNode(2);
1142             }
1143             is_deeply $t->printKeys, <
1144             SA0 5 1 2
1145             Lz3 1 3 4->5 6
1146             Ld2 2 5 6->9 10
1147             Rz3 1 7 8->5 6
1148             Rd1 4 9 10->1 2
1149             Lz4 1 11 12->13 14
1150             Ld3 2 13 14->17 18
1151             Rz4 1 15 16->13 14
1152             Rd2 3 17 18->9 10
1153             Rr3 2 19 20->17 18
1154             Rz4 1 21 22->19 20
1155             END
1156             #save $t;
1157              
1158             for my $n($t->inorder)
1159             {$n->setKeysPerNode(1);
1160             }
1161             is_deeply $t->printKeys, <
1162             SA0 6 1
1163             Lz4 1 2->3
1164             Ld3 2 3->5
1165             Rz4 1 4->3
1166             Ld2 3 5->9
1167             Lz4 1 6->7
1168             Rd3 2 7->5
1169             Rz4 1 8->7
1170             Rd1 5 9->1
1171             Lz5 1 10->11
1172             Ld4 2 11->13
1173             Rz5 1 12->11
1174             Ld3 3 13->17
1175             Lz5 1 14->15
1176             Rd4 2 15->13
1177             Rz5 1 16->15
1178             Rd2 4 17->9
1179             Lz4 1 18->19
1180             Rd3 3 19->17
1181             Lz5 1 20->21
1182             Rd4 2 21->19
1183             Rz5 1 22->21
1184             END
1185             #save $t;
1186              
1187             $_->setKeysPerNode(2) for $t->inorder;
1188             is_deeply $t->printKeys, <
1189             SA0 5 1 2
1190             Lz3 1 3 4->5 6
1191             Ld2 2 5 6->9 10
1192             Rz3 1 7 8->5 6
1193             Rd1 4 9 10->1 2
1194             Lz4 1 11 12->13 14
1195             Ld3 2 13 14->17 18
1196             Rz4 1 15 16->13 14
1197             Rd2 3 17 18->9 10
1198             Lz4 1 19 20->21 22
1199             Rl3 2 21 22->17 18
1200             END
1201             #save $t;
1202              
1203             $_->setKeysPerNode(4) for $t->inorder;
1204             is_deeply $t->printKeys, <
1205             SA0 4 1 2 3 4
1206             Lz2 1 5 6 7 8->9 10 11 12
1207             Rd1 3 9 10 11 12->1 2 3 4
1208             Lz3 1 13 14 15 16->17 18 19 20
1209             Rd2 2 17 18 19 20->9 10 11 12
1210             Rz3 1 21 22->17 18 19 20
1211             END
1212             #save $t;
1213             }
1214              
1215              
1216             =head2 names($tree)
1217              
1218             Names of all nodes in a tree in order
1219              
1220             Parameter Description
1221             1 $tree Tree
1222              
1223             B
1224              
1225              
1226             if (1)
1227             {my sub randomLoad($$$) # Randomly load different size nodes
1228             {my ($N, $keys, $height) = @_; # Number of elements, number of keys per node, expected height
1229              
1230             lll "Random load $keys";
1231              
1232             srand(1); # Same randomization
1233             my $t = Tree::Bulk::new->setKeysPerNode($keys);
1234             for my $r(randomizeArray 1..$N)
1235             {$debug = $r == 74;
1236             $t->insert($r, 2 * $r);
1237             $t->check;
1238             }
1239              
1240             is_deeply $t->actualHeight, $height; # Check height
1241             confess unless $t->actualHeight == $height;
1242              
1243             is_deeply join(' ', 1..$N), $t->names; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1244              
1245              
1246             my %t = map {$_=>2*$_} 1..$N;
1247             for my $r(randomizeArray 1..$N) # Delete in random order
1248             {$t->delete ($r);
1249             delete $t{$r};
1250             checkAgainstHash $t, %t;
1251             check($t);
1252             }
1253              
1254             ok $t->empty;
1255             is_deeply $t->actualHeight, 1;
1256             }
1257              
1258             randomLoad(222, 1, 11);
1259             randomLoad(222, 8, 8);
1260             randomLoad(222, 4, 9);
1261             }
1262              
1263              
1264             =head2 balance($t)
1265              
1266             Balance a node
1267              
1268             Parameter Description
1269             1 $t Tree
1270              
1271             B
1272              
1273              
1274             if (1)
1275             {lll "Balance";
1276             my $t = Tree::Bulk::new->setKeysPerNode(1);
1277              
1278             my $a = node(1,2) ->setKeysPerNode(1);
1279             my $b = node(2,4) ->setKeysPerNode(1);
1280             my $c = node(6,12)->setKeysPerNode(1);
1281             my $d = node(5,10)->setKeysPerNode(1);
1282             my $e = node(4,8) ->setKeysPerNode(1);
1283             my $f = node(3,6) ->setKeysPerNode(1);
1284             $a->right = $b; $b->up = $a;
1285             $b->right = $c; $c->up = $b;
1286             $c->left = $d; $d->up = $c;
1287             $d->left = $e; $e->up = $d;
1288             $e->left = $f; $f->up = $e;
1289             $f->setHeights(1);
1290             is_deeply $a->printKeys, <
1291             SA0 4 1
1292             Lr2 2 2->4
1293             Rz3 1 3->2
1294             Rd1 3 4->1
1295             Lz3 1 5->6
1296             Rl2 2 6->4
1297             END
1298             #save $a;
1299              
1300              
1301             $b->balance; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1302              
1303             is_deeply $a->printKeys, <
1304             SA0 4 1
1305             Lr2 2 2->4
1306             Rz3 1 3->2
1307             Rd1 3 4->1
1308             Lz3 1 5->6
1309             Rl2 2 6->4
1310             END
1311             #save $a;
1312             }
1313              
1314              
1315             =head2 insert($tree, $key, $data)
1316              
1317             Insert a key and some data into a tree
1318              
1319             Parameter Description
1320             1 $tree Tree
1321             2 $key Key
1322             3 $data Data
1323              
1324             B
1325              
1326              
1327             if (1)
1328             {lll "Insert";
1329             my $N = 23;
1330             my $t = Tree::Bulk::new->setKeysPerNode(1);
1331             for(1..$N)
1332              
1333             {$t->insert($_, 2 * $_); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1334              
1335             }
1336              
1337             is_deeply $t->printKeys, <
1338             SA0 8 1
1339             Lz4 1 2->3
1340             Ld3 2 3->5
1341             Rz4 1 4->3
1342             Ld2 3 5->9
1343             Lz4 1 6->7
1344             Rd3 2 7->5
1345             Rz4 1 8->7
1346             Rd1 7 9->1
1347             Lz4 1 10->11
1348             Ld3 2 11->13
1349             Rz4 1 12->11
1350             Rd2 6 13->9
1351             Lz5 1 14->15
1352             Ld4 2 15->17
1353             Rz5 1 16->15
1354             Rd3 5 17->13
1355             Lz5 1 18->19
1356             Rd4 4 19->17
1357             Lz6 1 20->21
1358             Rd5 3 21->19
1359             Rr6 2 22->21
1360             Rz7 1 23->22
1361             END
1362             #save $t;
1363             ok $t->height == 8;
1364             }
1365              
1366              
1367             =head2 find($tree, $key)
1368              
1369             Find a key in a tree and returns its data
1370              
1371             Parameter Description
1372             1 $tree Tree
1373             2 $key Key
1374              
1375             B
1376              
1377              
1378             if (1)
1379             {my $t = Tree::Bulk::new;
1380             $t->insert($_, $_*$_) for 1..20;
1381              
1382             ok !find($t, 0); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1383              
1384              
1385             ok !find($t, 21); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1386              
1387              
1388             ok find($t, $_) == $_ * $_ for qw(1 5 10 11 15 20); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1389              
1390             }
1391              
1392              
1393             =head2 first($n)
1394              
1395             First node in a tree
1396              
1397             Parameter Description
1398             1 $n Tree
1399              
1400             B
1401              
1402              
1403             if (1)
1404             {my $N = 220;
1405             my $t = Tree::Bulk::new;
1406              
1407             for(reverse 1..$N)
1408             {$t->insert($_, 2*$_);
1409             }
1410              
1411             is_deeply $t->actualHeight, 10;
1412              
1413             if (1)
1414             {my @n;
1415              
1416             for (my $n = $t->first; $n; $n = $n->next) # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1417              
1418             {push @n, $n->keys->@*
1419             }
1420             is_deeply \@n, [1..$N];
1421             }
1422              
1423             if (1)
1424             {my @p;
1425             for my $p(reverse $t->inorder)
1426             {push @p, reverse $p->keys->@*;
1427             }
1428             is_deeply \@p, [reverse 1..$N];
1429             }
1430              
1431             my @p;
1432             for(my $p = $t->last; $p; $p = $p->prev)
1433             {push @p, reverse $p->keys->@*
1434             }
1435             is_deeply \@p, [reverse 1..$N];
1436              
1437             my %t = map {$_=>2*$_} 1..$N;
1438             for my $i(0..3)
1439             {for my $j(map {4 * $_-$i} 1..$N/4)
1440             {$t->delete ($j);
1441             delete $t{$j};
1442             checkAgainstHash $t, %t;
1443             }
1444             }
1445              
1446             ok $t->empty;
1447             is_deeply $t->actualHeight, 1;
1448             }
1449              
1450              
1451             =head2 last($n)
1452              
1453             Last node in a tree
1454              
1455             Parameter Description
1456             1 $n Tree
1457              
1458             B
1459              
1460              
1461             if (1)
1462             {my $N = 220;
1463             my $t = Tree::Bulk::new;
1464              
1465             for(reverse 1..$N)
1466             {$t->insert($_, 2*$_);
1467             }
1468              
1469             is_deeply $t->actualHeight, 10;
1470              
1471             if (1)
1472             {my @n;
1473             for (my $n = $t->first; $n; $n = $n->next)
1474             {push @n, $n->keys->@*
1475             }
1476             is_deeply \@n, [1..$N];
1477             }
1478              
1479             if (1)
1480             {my @p;
1481             for my $p(reverse $t->inorder)
1482             {push @p, reverse $p->keys->@*;
1483             }
1484             is_deeply \@p, [reverse 1..$N];
1485             }
1486              
1487             my @p;
1488              
1489             for(my $p = $t->last; $p; $p = $p->prev) # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1490              
1491             {push @p, reverse $p->keys->@*
1492             }
1493             is_deeply \@p, [reverse 1..$N];
1494              
1495             my %t = map {$_=>2*$_} 1..$N;
1496             for my $i(0..3)
1497             {for my $j(map {4 * $_-$i} 1..$N/4)
1498             {$t->delete ($j);
1499             delete $t{$j};
1500             checkAgainstHash $t, %t;
1501             }
1502             }
1503              
1504             ok $t->empty;
1505             is_deeply $t->actualHeight, 1;
1506             }
1507              
1508              
1509             =head2 next($tree)
1510              
1511             Next node in order
1512              
1513             Parameter Description
1514             1 $tree Tree
1515              
1516             B
1517              
1518              
1519             if (1)
1520             {my $N = 220;
1521             my $t = Tree::Bulk::new;
1522              
1523             for(reverse 1..$N)
1524             {$t->insert($_, 2*$_);
1525             }
1526              
1527             is_deeply $t->actualHeight, 10;
1528              
1529             if (1)
1530             {my @n;
1531              
1532             for (my $n = $t->first; $n; $n = $n->next) # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1533              
1534             {push @n, $n->keys->@*
1535             }
1536             is_deeply \@n, [1..$N];
1537             }
1538              
1539             if (1)
1540             {my @p;
1541             for my $p(reverse $t->inorder)
1542             {push @p, reverse $p->keys->@*;
1543             }
1544             is_deeply \@p, [reverse 1..$N];
1545             }
1546              
1547             my @p;
1548             for(my $p = $t->last; $p; $p = $p->prev)
1549             {push @p, reverse $p->keys->@*
1550             }
1551             is_deeply \@p, [reverse 1..$N];
1552              
1553             my %t = map {$_=>2*$_} 1..$N;
1554             for my $i(0..3)
1555             {for my $j(map {4 * $_-$i} 1..$N/4)
1556             {$t->delete ($j);
1557             delete $t{$j};
1558             checkAgainstHash $t, %t;
1559             }
1560             }
1561              
1562             ok $t->empty;
1563             is_deeply $t->actualHeight, 1;
1564             }
1565              
1566              
1567             =head2 prev($tree)
1568              
1569             Previous node in order
1570              
1571             Parameter Description
1572             1 $tree Tree
1573              
1574             B
1575              
1576              
1577             if (1)
1578             {my $N = 220;
1579             my $t = Tree::Bulk::new;
1580              
1581             for(reverse 1..$N)
1582             {$t->insert($_, 2*$_);
1583             }
1584              
1585             is_deeply $t->actualHeight, 10;
1586              
1587             if (1)
1588             {my @n;
1589             for (my $n = $t->first; $n; $n = $n->next)
1590             {push @n, $n->keys->@*
1591             }
1592             is_deeply \@n, [1..$N];
1593             }
1594              
1595             if (1)
1596             {my @p;
1597             for my $p(reverse $t->inorder)
1598             {push @p, reverse $p->keys->@*;
1599             }
1600             is_deeply \@p, [reverse 1..$N];
1601             }
1602              
1603             my @p;
1604              
1605             for(my $p = $t->last; $p; $p = $p->prev) # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1606              
1607             {push @p, reverse $p->keys->@*
1608             }
1609             is_deeply \@p, [reverse 1..$N];
1610              
1611             my %t = map {$_=>2*$_} 1..$N;
1612             for my $i(0..3)
1613             {for my $j(map {4 * $_-$i} 1..$N/4)
1614             {$t->delete ($j);
1615             delete $t{$j};
1616             checkAgainstHash $t, %t;
1617             }
1618             }
1619              
1620             ok $t->empty;
1621             is_deeply $t->actualHeight, 1;
1622             }
1623              
1624              
1625             =head2 inorder($tree)
1626              
1627             Return a list of all the nodes in a tree in order
1628              
1629             Parameter Description
1630             1 $tree Tree
1631              
1632             B
1633              
1634              
1635             if (1)
1636             {my $N = 220;
1637             my $t = Tree::Bulk::new;
1638              
1639             for(reverse 1..$N)
1640             {$t->insert($_, 2*$_);
1641             }
1642              
1643             is_deeply $t->actualHeight, 10;
1644              
1645             if (1)
1646             {my @n;
1647             for (my $n = $t->first; $n; $n = $n->next)
1648             {push @n, $n->keys->@*
1649             }
1650             is_deeply \@n, [1..$N];
1651             }
1652              
1653             if (1)
1654             {my @p;
1655              
1656             for my $p(reverse $t->inorder) # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1657              
1658             {push @p, reverse $p->keys->@*;
1659             }
1660             is_deeply \@p, [reverse 1..$N];
1661             }
1662              
1663             my @p;
1664             for(my $p = $t->last; $p; $p = $p->prev)
1665             {push @p, reverse $p->keys->@*
1666             }
1667             is_deeply \@p, [reverse 1..$N];
1668              
1669             my %t = map {$_=>2*$_} 1..$N;
1670             for my $i(0..3)
1671             {for my $j(map {4 * $_-$i} 1..$N/4)
1672             {$t->delete ($j);
1673             delete $t{$j};
1674             checkAgainstHash $t, %t;
1675             }
1676             }
1677              
1678             ok $t->empty;
1679             is_deeply $t->actualHeight, 1;
1680             }
1681              
1682              
1683             =head2 delete($tree, $key)
1684              
1685             Delete a key in a tree
1686              
1687             Parameter Description
1688             1 $tree Tree
1689             2 $key Key
1690              
1691             B
1692              
1693              
1694             if (1)
1695             {lll "Delete";
1696             my $N = 28;
1697             my $t = Tree::Bulk::new->setKeysPerNode(1);
1698             for(1..$N)
1699             {$t->insert($_, 2 * $_);
1700             }
1701              
1702             is_deeply $t->printKeys, <
1703             SA0 8 1
1704             Lz4 1 2->3
1705             Ld3 2 3->5
1706             Rz4 1 4->3
1707             Ld2 3 5->9
1708             Lz4 1 6->7
1709             Rd3 2 7->5
1710             Rz4 1 8->7
1711             Rd1 7 9->1
1712             Lz5 1 10->11
1713             Ld4 2 11->13
1714             Rz5 1 12->11
1715             Ld3 3 13->17
1716             Lz5 1 14->15
1717             Rd4 2 15->13
1718             Rz5 1 16->15
1719             Rd2 6 17->9
1720             Lz5 1 18->19
1721             Ld4 2 19->21
1722             Rz5 1 20->19
1723             Rd3 5 21->17
1724             Lz5 1 22->23
1725             Rd4 4 23->21
1726             Lz6 1 24->25
1727             Rd5 3 25->23
1728             Lz7 1 26->27
1729             Rd6 2 27->25
1730             Rz7 1 28->27
1731             END
1732             #save $t;
1733              
1734             for my $k(reverse 1..$N)
1735              
1736             {$t->delete($k); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1737              
1738             is_deeply $t->printKeys, <
1739             SA0 5 1
1740             Lz4 1 2->3
1741             Ld3 2 3->5
1742             Rz4 1 4->3
1743             Ld2 3 5->9
1744             Lz4 1 6->7
1745             Rd3 2 7->5
1746             Rz4 1 8->7
1747             Rd1 4 9->1
1748             Lz4 1 10->11
1749             Ld3 2 11->13
1750             Rz4 1 12->11
1751             Rd2 3 13->9
1752             Lz4 1 14->15
1753             Rd3 2 15->13
1754             Rz4 1 16->15
1755             END
1756             #save $t if $k == 17;
1757              
1758             is_deeply $t->printKeys, <
1759             SA0 4 1
1760             Lz3 1 2->3
1761             Ld2 2 3->5
1762             Rz3 1 4->3
1763             Rd1 3 5->1
1764             Lz3 1 6->7
1765             Rd2 2 7->5
1766             Rz3 1 8->7
1767             END
1768             #save $t if $k == 9;
1769              
1770             is_deeply $t->printKeys, <
1771             SA0 4 1
1772             Lz2 1 2->3
1773             Rd1 3 3->1
1774             Lz3 1 4->5
1775             Rl2 2 5->3
1776             END
1777             #save $t if $k == 6;
1778              
1779             is_deeply $t->printKeys, <
1780             SA0 3 1
1781             Rr1 2 2->1
1782             Rz2 1 3->2
1783             END
1784             #save $t if $k == 4;
1785              
1786             is_deeply $t->printKeys, <
1787             SA0 2 1
1788             Rz1 1 2->1
1789             END
1790             #save $t if $k == 3;
1791              
1792             is_deeply $t->printKeys, <
1793             Sz0 1
1794             END
1795             #save $t if $k == 1;
1796             }
1797             }
1798              
1799              
1800             =head2 printKeys($t)
1801              
1802             Print the keys in a tree
1803              
1804             Parameter Description
1805             1 $t Tree
1806              
1807             B
1808              
1809              
1810             if (1)
1811             {lll "Insert";
1812             my $N = 23;
1813             my $t = Tree::Bulk::new->setKeysPerNode(1);
1814             for(1..$N)
1815             {$t->insert($_, 2 * $_);
1816             }
1817              
1818              
1819             is_deeply $t->printKeys, <
1820              
1821             SA0 8 1
1822             Lz4 1 2->3
1823             Ld3 2 3->5
1824             Rz4 1 4->3
1825             Ld2 3 5->9
1826             Lz4 1 6->7
1827             Rd3 2 7->5
1828             Rz4 1 8->7
1829             Rd1 7 9->1
1830             Lz4 1 10->11
1831             Ld3 2 11->13
1832             Rz4 1 12->11
1833             Rd2 6 13->9
1834             Lz5 1 14->15
1835             Ld4 2 15->17
1836             Rz5 1 16->15
1837             Rd3 5 17->13
1838             Lz5 1 18->19
1839             Rd4 4 19->17
1840             Lz6 1 20->21
1841             Rd5 3 21->19
1842             Rr6 2 22->21
1843             Rz7 1 23->22
1844             END
1845             #save $t;
1846             ok $t->height == 8;
1847             }
1848              
1849              
1850             =head2 setKeysPerNode($tree, $N)
1851              
1852             Set the number of keys for the current node
1853              
1854             Parameter Description
1855             1 $tree Tree
1856             2 $N Keys per node to be set
1857              
1858             B
1859              
1860              
1861             if (1)
1862             {lll "Split and Refill";
1863             my $N = 22;
1864             my $t = Tree::Bulk::new;
1865             for my $k(1..$N)
1866             {$t->insert($k, 2 * $k);
1867             }
1868              
1869             is_deeply $t->name, "1 2 3 4";
1870              
1871             is_deeply $t->printKeys, <
1872             SA0 4 1 2 3 4
1873             Lz2 1 5 6 7 8->9 10 11 12
1874             Rd1 3 9 10 11 12->1 2 3 4
1875             Lz3 1 13 14 15 16->17 18 19 20
1876             Rd2 2 17 18 19 20->9 10 11 12
1877             Rz3 1 21 22->17 18 19 20
1878             END
1879             #save $t;
1880              
1881             for my $n($t->inorder)
1882              
1883             {$n->setKeysPerNode(2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1884              
1885             }
1886             is_deeply $t->printKeys, <
1887             SA0 5 1 2
1888             Lz3 1 3 4->5 6
1889             Ld2 2 5 6->9 10
1890             Rz3 1 7 8->5 6
1891             Rd1 4 9 10->1 2
1892             Lz4 1 11 12->13 14
1893             Ld3 2 13 14->17 18
1894             Rz4 1 15 16->13 14
1895             Rd2 3 17 18->9 10
1896             Rr3 2 19 20->17 18
1897             Rz4 1 21 22->19 20
1898             END
1899             #save $t;
1900              
1901             for my $n($t->inorder)
1902              
1903             {$n->setKeysPerNode(1); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1904              
1905             }
1906             is_deeply $t->printKeys, <
1907             SA0 6 1
1908             Lz4 1 2->3
1909             Ld3 2 3->5
1910             Rz4 1 4->3
1911             Ld2 3 5->9
1912             Lz4 1 6->7
1913             Rd3 2 7->5
1914             Rz4 1 8->7
1915             Rd1 5 9->1
1916             Lz5 1 10->11
1917             Ld4 2 11->13
1918             Rz5 1 12->11
1919             Ld3 3 13->17
1920             Lz5 1 14->15
1921             Rd4 2 15->13
1922             Rz5 1 16->15
1923             Rd2 4 17->9
1924             Lz4 1 18->19
1925             Rd3 3 19->17
1926             Lz5 1 20->21
1927             Rd4 2 21->19
1928             Rz5 1 22->21
1929             END
1930             #save $t;
1931              
1932              
1933             $_->setKeysPerNode(2) for $t->inorder; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1934              
1935             is_deeply $t->printKeys, <
1936             SA0 5 1 2
1937             Lz3 1 3 4->5 6
1938             Ld2 2 5 6->9 10
1939             Rz3 1 7 8->5 6
1940             Rd1 4 9 10->1 2
1941             Lz4 1 11 12->13 14
1942             Ld3 2 13 14->17 18
1943             Rz4 1 15 16->13 14
1944             Rd2 3 17 18->9 10
1945             Lz4 1 19 20->21 22
1946             Rl3 2 21 22->17 18
1947             END
1948             #save $t;
1949              
1950              
1951             $_->setKeysPerNode(4) for $t->inorder; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1952              
1953             is_deeply $t->printKeys, <
1954             SA0 4 1 2 3 4
1955             Lz2 1 5 6 7 8->9 10 11 12
1956             Rd1 3 9 10 11 12->1 2 3 4
1957             Lz3 1 13 14 15 16->17 18 19 20
1958             Rd2 2 17 18 19 20->9 10 11 12
1959             Rz3 1 21 22->17 18 19 20
1960             END
1961             #save $t;
1962             }
1963              
1964              
1965             =head2 printKeysAndData($t)
1966              
1967             Print the mapping from keys to data in a tree
1968              
1969             Parameter Description
1970             1 $t Tree
1971              
1972             B
1973              
1974              
1975             if (1)
1976             {my $N = 22;
1977             my $t = Tree::Bulk::new;
1978             ok $t->empty;
1979             ok $t->leaf;
1980              
1981             for(1..$N)
1982             {$t->insert($_, 2 * $_);
1983             }
1984              
1985             ok $t->right->duplex;
1986             is_deeply actualHeight($t), 4;
1987              
1988             is_deeply $t->printKeys, <
1989             SA0 4 1 2 3 4
1990             Lz2 1 5 6 7 8->9 10 11 12
1991             Rd1 3 9 10 11 12->1 2 3 4
1992             Lz3 1 13 14 15 16->17 18 19 20
1993             Rd2 2 17 18 19 20->9 10 11 12
1994             Rz3 1 21 22->17 18 19 20
1995             END
1996             #save $t;
1997              
1998              
1999             is_deeply $t->printKeysAndData, <
2000              
2001             1 2
2002             2 4
2003             3 6
2004             4 8
2005             5 10
2006             6 12
2007             7 14
2008             8 16
2009             9 18
2010             10 20
2011             11 22
2012             12 24
2013             13 26
2014             14 28
2015             15 30
2016             16 32
2017             17 34
2018             18 36
2019             19 38
2020             20 40
2021             21 42
2022             22 44
2023             END
2024              
2025             my %t = map {$_=>2*$_} 1..$N;
2026              
2027             for(map {2 * $_} 1..$N/2)
2028             {$t->delete($_);
2029             delete $t{$_};
2030             checkAgainstHash $t, %t;
2031             }
2032              
2033             is_deeply $t->printKeys, <
2034             SA0 3 1 3 5 7
2035             Rr1 2 9 11 13 15->1 3 5 7
2036             Rz2 1 17 19 21->9 11 13 15
2037             END
2038             #save($t);
2039              
2040              
2041             is_deeply $t->printKeysAndData, <
2042              
2043             1 2
2044             3 6
2045             5 10
2046             7 14
2047             9 18
2048             11 22
2049             13 26
2050             15 30
2051             17 34
2052             19 38
2053             21 42
2054             END
2055              
2056             for(map {2 * $_-1} 1..$N/2)
2057             {$t->delete($_);
2058             delete $t{$_};
2059             checkAgainstHash $t, %t;
2060             }
2061              
2062             is_deeply $t->printKeys, <
2063             Sz0 1
2064             END
2065             #save($t);
2066             }
2067              
2068              
2069              
2070             =head2 Tree::Bulk Definition
2071              
2072              
2073             Bulk tree node
2074              
2075              
2076              
2077              
2078             =head3 Output fields
2079              
2080              
2081             =head4 data
2082              
2083             Data corresponding to each key
2084              
2085             =head4 height
2086              
2087             Height of node
2088              
2089             =head4 keys
2090              
2091             Array of data items for this node
2092              
2093             =head4 keysPerNode
2094              
2095             Maximum number of keys per node
2096              
2097             =head4 left
2098              
2099             Left node
2100              
2101             =head4 right
2102              
2103             Right node
2104              
2105             =head4 up
2106              
2107             Parent node
2108              
2109              
2110              
2111             =head1 Attributes
2112              
2113              
2114             The following is a list of all the attributes in this package. A method coded
2115             with the same name in your package will over ride the method of the same name
2116             in this package and thus provide your value for the attribute in place of the
2117             default value supplied for this attribute by this package.
2118              
2119             =head2 Replaceable Attribute List
2120              
2121              
2122             new
2123              
2124              
2125             =head2 new
2126              
2127             Create a new tree
2128              
2129              
2130              
2131              
2132             =head1 Private Methods
2133              
2134             =head2 node($key, $data, $up, $side)
2135              
2136             Create a new bulk tree node
2137              
2138             Parameter Description
2139             1 $key Key
2140             2 $data $data
2141             3 $up Parent node
2142             4 $side Side of parent node
2143              
2144             =head2 setHeights($tree)
2145              
2146             Set heights along path to root
2147              
2148             Parameter Description
2149             1 $tree Tree
2150              
2151             B
2152              
2153              
2154             if (1)
2155             {lll "Balance";
2156             my $t = Tree::Bulk::new->setKeysPerNode(1);
2157              
2158             my $a = node(1,2) ->setKeysPerNode(1);
2159             my $b = node(2,4) ->setKeysPerNode(1);
2160             my $c = node(6,12)->setKeysPerNode(1);
2161             my $d = node(5,10)->setKeysPerNode(1);
2162             my $e = node(4,8) ->setKeysPerNode(1);
2163             my $f = node(3,6) ->setKeysPerNode(1);
2164             $a->right = $b; $b->up = $a;
2165             $b->right = $c; $c->up = $b;
2166             $c->left = $d; $d->up = $c;
2167             $d->left = $e; $e->up = $d;
2168             $e->left = $f; $f->up = $e;
2169              
2170             $f->setHeights(1); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2171              
2172             is_deeply $a->printKeys, <
2173             SA0 4 1
2174             Lr2 2 2->4
2175             Rz3 1 3->2
2176             Rd1 3 4->1
2177             Lz3 1 5->6
2178             Rl2 2 6->4
2179             END
2180             #save $a;
2181              
2182             $b->balance;
2183             is_deeply $a->printKeys, <
2184             SA0 4 1
2185             Lr2 2 2->4
2186             Rz3 1 3->2
2187             Rd1 3 4->1
2188             Lz3 1 5->6
2189             Rl2 2 6->4
2190             END
2191             #save $a;
2192             }
2193              
2194              
2195             =head2 actualHeight($tree)
2196              
2197             Get the height of a node
2198              
2199             Parameter Description
2200             1 $tree Tree
2201              
2202             B
2203              
2204              
2205             if (1)
2206             {my $N = 22;
2207             my $t = Tree::Bulk::new;
2208             ok $t->empty;
2209             ok $t->leaf;
2210              
2211             for(1..$N)
2212             {$t->insert($_, 2 * $_);
2213             }
2214              
2215             ok $t->right->duplex;
2216              
2217             is_deeply actualHeight($t), 4; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2218              
2219              
2220             is_deeply $t->printKeys, <
2221             SA0 4 1 2 3 4
2222             Lz2 1 5 6 7 8->9 10 11 12
2223             Rd1 3 9 10 11 12->1 2 3 4
2224             Lz3 1 13 14 15 16->17 18 19 20
2225             Rd2 2 17 18 19 20->9 10 11 12
2226             Rz3 1 21 22->17 18 19 20
2227             END
2228             #save $t;
2229              
2230             is_deeply $t->printKeysAndData, <
2231             1 2
2232             2 4
2233             3 6
2234             4 8
2235             5 10
2236             6 12
2237             7 14
2238             8 16
2239             9 18
2240             10 20
2241             11 22
2242             12 24
2243             13 26
2244             14 28
2245             15 30
2246             16 32
2247             17 34
2248             18 36
2249             19 38
2250             20 40
2251             21 42
2252             22 44
2253             END
2254              
2255             my %t = map {$_=>2*$_} 1..$N;
2256              
2257             for(map {2 * $_} 1..$N/2)
2258             {$t->delete($_);
2259             delete $t{$_};
2260             checkAgainstHash $t, %t;
2261             }
2262              
2263             is_deeply $t->printKeys, <
2264             SA0 3 1 3 5 7
2265             Rr1 2 9 11 13 15->1 3 5 7
2266             Rz2 1 17 19 21->9 11 13 15
2267             END
2268             #save($t);
2269              
2270             is_deeply $t->printKeysAndData, <
2271             1 2
2272             3 6
2273             5 10
2274             7 14
2275             9 18
2276             11 22
2277             13 26
2278             15 30
2279             17 34
2280             19 38
2281             21 42
2282             END
2283              
2284             for(map {2 * $_-1} 1..$N/2)
2285             {$t->delete($_);
2286             delete $t{$_};
2287             checkAgainstHash $t, %t;
2288             }
2289              
2290             is_deeply $t->printKeys, <
2291             Sz0 1
2292             END
2293             #save($t);
2294             }
2295              
2296              
2297             =head2 maximum($a, $b)
2298              
2299             Maximum of two numbers
2300              
2301             Parameter Description
2302             1 $a First
2303             2 $b Second
2304              
2305             B
2306              
2307              
2308             if (1)
2309              
2310             {is_deeply maximum(1,2), 2; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2311              
2312              
2313             is_deeply maximum(2,1), 2; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2314              
2315             }
2316              
2317              
2318             =head2 setHeight($tree)
2319              
2320             Set height of a tree from its left and right trees
2321              
2322             Parameter Description
2323             1 $tree Tree
2324              
2325             =head2 rotateLeft($n)
2326              
2327             Rotate a node left
2328              
2329             Parameter Description
2330             1 $n Node
2331              
2332             B
2333              
2334              
2335             if (1)
2336             {lll "Rotate";
2337             my $a = node(1,2)->setKeysPerNode(1);
2338             my $b = node(2,4)->setKeysPerNode(1);
2339             my $c = node(3,6)->setKeysPerNode(1);
2340             my $d = node(4,8)->setKeysPerNode(1);
2341             $a->right = $b; $b->up = $a;
2342             $b->right = $c; $c->up = $b;
2343             $c->right = $d; $d->up = $c;
2344             $d->setHeights(1);
2345              
2346             is_deeply $a->printKeys, <
2347             SA0 3 1
2348             Lz2 1 2->3
2349             Rd1 2 3->1
2350             Rz2 1 4->3
2351             END
2352             #save $a;
2353              
2354             $b->rotateLeft; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2355              
2356             is_deeply $a->printKeys, <
2357             SA0 3 1
2358             Lz2 1 2->3
2359             Rd1 2 3->1
2360             Rz2 1 4->3
2361             END
2362             #save $a;
2363              
2364              
2365             $c->rotateLeft; $c->setHeights(2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2366              
2367             is_deeply $a->printKeys, <
2368             SA0 3 1
2369             Lz2 1 2->3
2370             Rd1 2 3->1
2371             Rz2 1 4->3
2372             END
2373             #save $a;
2374              
2375             $d->rotateRight; $d->setHeights(1);
2376             is_deeply $a->printKeys, <
2377             SA0 3 1
2378             Lz2 1 2->3
2379             Rd1 2 3->1
2380             Rz2 1 4->3
2381             END
2382             #save $a;
2383              
2384             $c->rotateRight; $c->setHeights(2);
2385             is_deeply $a->printKeys, <
2386             SA0 3 1
2387             Lz2 1 2->3
2388             Rd1 2 3->1
2389             Rz2 1 4->3
2390             END
2391             #save $a;
2392             }
2393              
2394              
2395             =head2 rotateRight($n)
2396              
2397             Rotate a node right
2398              
2399             Parameter Description
2400             1 $n Node
2401              
2402             B
2403              
2404              
2405             if (1)
2406             {lll "Rotate";
2407             my $a = node(1,2)->setKeysPerNode(1);
2408             my $b = node(2,4)->setKeysPerNode(1);
2409             my $c = node(3,6)->setKeysPerNode(1);
2410             my $d = node(4,8)->setKeysPerNode(1);
2411             $a->right = $b; $b->up = $a;
2412             $b->right = $c; $c->up = $b;
2413             $c->right = $d; $d->up = $c;
2414             $d->setHeights(1);
2415              
2416             is_deeply $a->printKeys, <
2417             SA0 3 1
2418             Lz2 1 2->3
2419             Rd1 2 3->1
2420             Rz2 1 4->3
2421             END
2422             #save $a;
2423             $b->rotateLeft;
2424             is_deeply $a->printKeys, <
2425             SA0 3 1
2426             Lz2 1 2->3
2427             Rd1 2 3->1
2428             Rz2 1 4->3
2429             END
2430             #save $a;
2431              
2432             $c->rotateLeft; $c->setHeights(2);
2433             is_deeply $a->printKeys, <
2434             SA0 3 1
2435             Lz2 1 2->3
2436             Rd1 2 3->1
2437             Rz2 1 4->3
2438             END
2439             #save $a;
2440              
2441              
2442             $d->rotateRight; $d->setHeights(1); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2443              
2444             is_deeply $a->printKeys, <
2445             SA0 3 1
2446             Lz2 1 2->3
2447             Rd1 2 3->1
2448             Rz2 1 4->3
2449             END
2450             #save $a;
2451              
2452              
2453             $c->rotateRight; $c->setHeights(2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2454              
2455             is_deeply $a->printKeys, <
2456             SA0 3 1
2457             Lz2 1 2->3
2458             Rd1 2 3->1
2459             Rz2 1 4->3
2460             END
2461             #save $a;
2462             }
2463              
2464              
2465             =head2 insertUnchecked($tree, $key, $data)
2466              
2467             Insert a key and some data into a tree
2468              
2469             Parameter Description
2470             1 $tree Tree
2471             2 $key Key
2472             3 $data Data
2473              
2474             =head2 unchain($t)
2475              
2476             Remove a tree from the middle of a chain. A leaf is considered to be in the middle of a chain and so can be removed with this method
2477              
2478             Parameter Description
2479             1 $t Tree
2480              
2481             =head2 refillFromRight($target)
2482              
2483             Push a key to the target node from the next node
2484              
2485             Parameter Description
2486             1 $target Target tree
2487              
2488             =head2 refillFromLeft($target)
2489              
2490             Push a key to the target node from the previous node
2491              
2492             Parameter Description
2493             1 $target Target tree
2494              
2495             =head2 refill($tree)
2496              
2497             Refill a node so it has the expected number of keys
2498              
2499             Parameter Description
2500             1 $tree Tree
2501              
2502             =head2 printKeys2($t, $in, $g)
2503              
2504             print the keys for a tree
2505              
2506             Parameter Description
2507             1 $t Tree
2508             2 $in Indentation
2509             3 $g List of keys
2510              
2511             =head2 checkLRU($tree)
2512              
2513             Confirm pointers in tree
2514              
2515             Parameter Description
2516             1 $tree Tree
2517              
2518             =head2 check($tree)
2519              
2520             Confirm that each node in a tree is ordered correctly
2521              
2522             Parameter Description
2523             1 $tree Tree
2524              
2525             =head2 checkAgainstHash($t, %t)
2526              
2527             Check a tree against a hash
2528              
2529             Parameter Description
2530             1 $t Tree
2531             2 %t Expected
2532              
2533              
2534             =head1 Index
2535              
2536              
2537             1 L - Get the height of a node
2538              
2539             2 L - Balance a node
2540              
2541             3 L - Confirm that each node in a tree is ordered correctly
2542              
2543             4 L - Check a tree against a hash
2544              
2545             5 L - Confirm pointers in tree
2546              
2547             6 L - Delete a key in a tree
2548              
2549             7 L - Return the tree if it has left and right children
2550              
2551             8 L - Return the tree if it is empty
2552              
2553             9 L - Find a key in a tree and returns its data
2554              
2555             10 L - First node in a tree
2556              
2557             11 L - Return a list of all the nodes in a tree in order
2558              
2559             12 L - Insert a key and some data into a tree
2560              
2561             13 L - Insert a key and some data into a tree
2562              
2563             14 L - Return the tree if it is the left child
2564              
2565             15 L - Return the tree if it is the right child
2566              
2567             16 L - Return the tree if it is the root
2568              
2569             17 L - Last node in a tree
2570              
2571             18 L - Return the tree if it is a leaf
2572              
2573             19 L - Maximum of two numbers
2574              
2575             20 L - Name of a tree
2576              
2577             21 L - Names of all nodes in a tree in order
2578              
2579             22 L - Next node in order
2580              
2581             23 L - Create a new bulk tree node
2582              
2583             24 L - Previous node in order
2584              
2585             25 L - Print the keys in a tree
2586              
2587             26 L - print the keys for a tree
2588              
2589             27 L - Print the mapping from keys to data in a tree
2590              
2591             28 L - Refill a node so it has the expected number of keys
2592              
2593             29 L - Push a key to the target node from the previous node
2594              
2595             30 L - Push a key to the target node from the next node
2596              
2597             31 L - Return the root node of a tree
2598              
2599             32 L - Rotate a node left
2600              
2601             33 L - Rotate a node right
2602              
2603             34 L - Set height of a tree from its left and right trees
2604              
2605             35 L - Set heights along path to root
2606              
2607             36 L - Set the number of keys for the current node
2608              
2609             37 L - Return the tree if it has either a left child or a right child but not both.
2610              
2611             38 L - Return the tree if it has either a left child or a right child but not both and the child it has a leaf.
2612              
2613             39 L - Return the tree if it contains only the root node and nothing else
2614              
2615             40 L - Remove a tree from the middle of a chain.
2616              
2617             =head1 Installation
2618              
2619             This module is written in 100% Pure Perl and, thus, it is easy to read,
2620             comprehend, use, modify and install via B:
2621              
2622             sudo cpan install Tree::Bulk
2623              
2624             =head1 Author
2625              
2626             L
2627              
2628             L
2629              
2630             =head1 Copyright
2631              
2632             Copyright (c) 2016-2021 Philip R Brenan.
2633              
2634             This module is free software. It may be used, redistributed and/or modified
2635             under the same terms as Perl itself.
2636              
2637             =cut
2638              
2639              
2640              
2641             # Tests and documentation
2642              
2643             sub test
2644 1     1 0 84 {my $p = __PACKAGE__;
2645 1         11 binmode($_, ":utf8") for *STDOUT, *STDERR;
2646 1 50       70 return if eval "eof(${p}::DATA)";
2647 0           my $s = eval "join('', <${p}::DATA>)";
2648 0 0         $@ and die $@;
2649 0           eval $s;
2650 0 0         $@ and die $@;
2651 0           1
2652             }
2653              
2654             test unless caller;
2655              
2656             1;
2657             # podDocumentation
2658             #__DATA__
2659 1     1   7 use Time::HiRes qw(time);
  1         5  
  1         8  
2660 1     1   1008 use Test::More;
  1         68174  
  1         21  
2661              
2662             my $localTest = ((caller(1))[0]//'Tree::Bulk') eq "Tree::Bulk"; # Local testing mode
2663              
2664             Test::More->builder->output("/dev/null") if $localTest; # Reduce number of confirmation messages during testing
2665              
2666             if ($^O =~ m(bsd|linux)i) {plan tests => 90} # Supported systems
2667             else
2668             {plan skip_all =>qq(Not supported on: $^O);
2669             }
2670              
2671             my $start = time; # Tests
2672             #goto latest;
2673              
2674             if (1) #Tsimplex
2675             {lll "SetHeights";
2676             my $a = node(1,1)->setKeysPerNode(1);
2677             my $b = node(2,2)->setKeysPerNode(1);
2678             my $c = node(3,3)->setKeysPerNode(1);
2679             my $d = node(4,4)->setKeysPerNode(1);
2680             my $e = node(5,5);
2681             $a->right = $b; $b->up = $a;
2682             $b->right = $c; $c->up = $b;
2683             $c->right = $d; $d->up = $c;
2684             $d->right = $e; $e->up = $d;
2685              
2686             is_deeply $a->printKeys, <
2687             SA0 1 1
2688             Rr1 1 2->1
2689             Rr2 1 3->2
2690             Rr3 1 4->3
2691             Rz4 1 5->4
2692             END
2693             #save $a;
2694              
2695             $e->setHeights(1);
2696             is_deeply $a->printKeys, <
2697             SA0 4 1
2698             Rr1 3 2->1
2699             Lz3 1 3->4
2700             Rd2 2 4->2
2701             Rz3 1 5->4
2702             END
2703             #save $a;
2704             ok $b->simplex;
2705             ok !$c->simplex;
2706              
2707             $c->balance;
2708             is_deeply $a->printKeys, <
2709             SA0 4 1
2710             Rr1 3 2->1
2711             Lz3 1 3->4
2712             Rd2 2 4->2
2713             Rz3 1 5->4
2714             END
2715             #save $a;
2716              
2717             $b->balance;
2718             is_deeply $a->printKeys, <
2719             SA0 4 1
2720             Lr2 2 2->4
2721             Rz3 1 3->2
2722             Rd1 3 4->1
2723             Rz2 1 5->4
2724             END
2725             #save $a;
2726             }
2727              
2728             if (1) #TsimplexWithLeaf
2729             {lll "Balance";
2730             my $a = node(1,1)->setKeysPerNode(1); $a->height = 5;
2731             my $b = node(2,2)->setKeysPerNode(1); $b->height = 4;
2732             my $c = node(3,3)->setKeysPerNode(1); $c->height = 3;
2733             my $d = node(4,4)->setKeysPerNode(1); $d->height = 2;
2734             my $e = node(5,5); $e->height = 1;
2735             $a->right = $b; $b->up = $a;
2736             $b->right = $c; $c->up = $b;
2737             $c->right = $d; $d->up = $c;
2738             $d->right = $e; $e->up = $d;
2739              
2740             $e->balance;
2741             is_deeply $a->printKeys, <
2742             SA0 5 1
2743             Rr1 4 2->1
2744             Rr2 3 3->2
2745             Rr3 2 4->3
2746             Rz4 1 5->4
2747             END
2748             #save $a;
2749             ok $d->simplexWithLeaf;
2750             ok !$c->simplexWithLeaf;
2751              
2752             $d->balance;
2753             is_deeply $a->printKeys, <
2754             SA0 5 1
2755             Rr1 4 2->1
2756             Rr2 3 3->2
2757             Rr3 2 4->3
2758             Rz4 1 5->4
2759             END
2760             #save $a;
2761              
2762             $c->balance;
2763             is_deeply $a->printKeys, <
2764             SA0 5 1
2765             Rr1 3 2->1
2766             Lz3 1 3->4
2767             Rd2 2 4->2
2768             Rz3 1 5->4
2769             END
2770             #save $a;
2771              
2772             $b->balance;
2773             is_deeply $a->printKeys, <
2774             SA0 4 1
2775             Lr2 2 2->4
2776             Rz3 1 3->2
2777             Rd1 3 4->1
2778             Rz2 1 5->4
2779             END
2780             #save $a;
2781             }
2782              
2783             if (1)
2784             {lll "Leaf becomes non leaf";
2785             my $a = node(14,1)->setKeysPerNode(1); $a->height = 4;
2786             my $b = node(5,2) ->setKeysPerNode(1); $b->height = 3;
2787             my $c = node(4,3) ->setKeysPerNode(1); $c->height = 1;
2788             my $d = node(9,4) ->setKeysPerNode(1); $d->height = 1;
2789             my $e = node(10,5); $e->height = 2;
2790             $a->left = $b; $b->up = $a;
2791             $b->left = $c; $c->up = $b;
2792             $b->right = $e; $e->up = $b;
2793             $e->left = $d; $d->up = $e;
2794              
2795             is_deeply $a->printKeys, <
2796             Lz2 1 4->5
2797             Ld1 3 5->14
2798             Lz3 1 9->10
2799             Rl2 2 10->5
2800             SA0 4 14
2801             END
2802             #save $a;
2803              
2804             $a->delete(4);
2805             is_deeply $a->printKeys, <
2806             Lz2 1 5->9
2807             Ld1 2 9->14
2808             Rz2 1 10->9
2809             SA0 3 14
2810             END
2811             #save $a;
2812             }
2813              
2814             if (1)
2815             {lll "Unchain";
2816             my $t = Tree::Bulk::new->setKeysPerNode(1);
2817             my $a = node(1,2);
2818             my $b = node(2,4);
2819             my $c = node(3,6);
2820             my $d = node(4,8);
2821             my $e = node(5,10);
2822             $a->right = $b; $b->up = $a;
2823             $b->right = $d; $d->up = $b;
2824             $d->left = $c; $c->up = $d;
2825             $d->right = $e; $e->up = $d;
2826              
2827             is_deeply $a->printKeys, <
2828             SA0 1 1
2829             Rr1 1 2->1
2830             Lz3 1 3->4
2831             Rd2 1 4->2
2832             Rz3 1 5->4
2833             END
2834             #save $a;
2835             $b->unchain;
2836             is_deeply $a->printKeys, <
2837             SA0 3 1
2838             Lz2 1 3->4
2839             Rd1 2 4->1
2840             Rz2 1 5->4
2841             END
2842             #save $a;
2843             }
2844              
2845             if (1) #TrotateLeft #TrotateRight
2846             {lll "Rotate";
2847             my $a = node(1,2)->setKeysPerNode(1);
2848             my $b = node(2,4)->setKeysPerNode(1);
2849             my $c = node(3,6)->setKeysPerNode(1);
2850             my $d = node(4,8)->setKeysPerNode(1);
2851             $a->right = $b; $b->up = $a;
2852             $b->right = $c; $c->up = $b;
2853             $c->right = $d; $d->up = $c;
2854             $d->setHeights(1);
2855              
2856             is_deeply $a->printKeys, <
2857             SA0 3 1
2858             Lz2 1 2->3
2859             Rd1 2 3->1
2860             Rz2 1 4->3
2861             END
2862             #save $a;
2863             $b->rotateLeft;
2864             is_deeply $a->printKeys, <
2865             SA0 3 1
2866             Lz2 1 2->3
2867             Rd1 2 3->1
2868             Rz2 1 4->3
2869             END
2870             #save $a;
2871              
2872             $c->rotateLeft; $c->setHeights(2);
2873             is_deeply $a->printKeys, <
2874             SA0 3 1
2875             Lz2 1 2->3
2876             Rd1 2 3->1
2877             Rz2 1 4->3
2878             END
2879             #save $a;
2880              
2881             $d->rotateRight; $d->setHeights(1);
2882             is_deeply $a->printKeys, <
2883             SA0 3 1
2884             Lz2 1 2->3
2885             Rd1 2 3->1
2886             Rz2 1 4->3
2887             END
2888             #save $a;
2889              
2890             $c->rotateRight; $c->setHeights(2);
2891             is_deeply $a->printKeys, <
2892             SA0 3 1
2893             Lz2 1 2->3
2894             Rd1 2 3->1
2895             Rz2 1 4->3
2896             END
2897             #save $a;
2898             }
2899              
2900             if (1) #Tmaximum
2901             {is_deeply maximum(1,2), 2;
2902             is_deeply maximum(2,1), 2;
2903             }
2904              
2905             if (1) #Tempty #Tsingleton
2906             {lll "Balance";
2907             my $t = Tree::Bulk::new->setKeysPerNode(1);
2908             ok $t->empty;
2909             ok $t->singleton;
2910             }
2911              
2912             if (1) #Tbalance #TsetHeights
2913             {lll "Balance";
2914             my $t = Tree::Bulk::new->setKeysPerNode(1);
2915              
2916             my $a = node(1,2) ->setKeysPerNode(1);
2917             my $b = node(2,4) ->setKeysPerNode(1);
2918             my $c = node(6,12)->setKeysPerNode(1);
2919             my $d = node(5,10)->setKeysPerNode(1);
2920             my $e = node(4,8) ->setKeysPerNode(1);
2921             my $f = node(3,6) ->setKeysPerNode(1);
2922             $a->right = $b; $b->up = $a;
2923             $b->right = $c; $c->up = $b;
2924             $c->left = $d; $d->up = $c;
2925             $d->left = $e; $e->up = $d;
2926             $e->left = $f; $f->up = $e;
2927             $f->setHeights(1);
2928             is_deeply $a->printKeys, <
2929             SA0 4 1
2930             Lr2 2 2->4
2931             Rz3 1 3->2
2932             Rd1 3 4->1
2933             Lz3 1 5->6
2934             Rl2 2 6->4
2935             END
2936             #save $a;
2937              
2938             $b->balance;
2939             is_deeply $a->printKeys, <
2940             SA0 4 1
2941             Lr2 2 2->4
2942             Rz3 1 3->2
2943             Rd1 3 4->1
2944             Lz3 1 5->6
2945             Rl2 2 6->4
2946             END
2947             #save $a;
2948             }
2949              
2950             if (1) #TisLeftChild #TisRightChild #TisRoot #Tleaf #Tduplex #Troot
2951             {lll "Attributes";
2952             my $t = Tree::Bulk::new->setKeysPerNode(1);
2953             my $b = $t->insert(2,4);
2954             my $a = $t->insert(1,2);
2955             my $c = $t->insert(3,6);
2956             ok $a->isLeftChild;
2957             ok $c->isRightChild;
2958             ok !$a->isRightChild;
2959             ok !$c->isLeftChild;
2960             ok $b->isRoot;
2961             ok !$a->isRoot;
2962             ok !$c->isRoot;
2963             ok $a->leaf;
2964             ok $c->leaf;
2965             ok $b->duplex;
2966             ok $c->root == $b;
2967             ok $c->root != $a;
2968             }
2969              
2970             if (1) #Tinsert #Theight #TprintKeys
2971             {lll "Insert";
2972             my $N = 23;
2973             my $t = Tree::Bulk::new->setKeysPerNode(1);
2974             for(1..$N)
2975             {$t->insert($_, 2 * $_);
2976             }
2977              
2978             is_deeply $t->printKeys, <
2979             SA0 8 1
2980             Lz4 1 2->3
2981             Ld3 2 3->5
2982             Rz4 1 4->3
2983             Ld2 3 5->9
2984             Lz4 1 6->7
2985             Rd3 2 7->5
2986             Rz4 1 8->7
2987             Rd1 7 9->1
2988             Lz4 1 10->11
2989             Ld3 2 11->13
2990             Rz4 1 12->11
2991             Rd2 6 13->9
2992             Lz5 1 14->15
2993             Ld4 2 15->17
2994             Rz5 1 16->15
2995             Rd3 5 17->13
2996             Lz5 1 18->19
2997             Rd4 4 19->17
2998             Lz6 1 20->21
2999             Rd5 3 21->19
3000             Rr6 2 22->21
3001             Rz7 1 23->22
3002             END
3003             #save $t;
3004             ok $t->height == 8;
3005             }
3006              
3007             if (1) #Tdelete
3008             {lll "Delete";
3009             my $N = 28;
3010             my $t = Tree::Bulk::new->setKeysPerNode(1);
3011             for(1..$N)
3012             {$t->insert($_, 2 * $_);
3013             }
3014              
3015             is_deeply $t->printKeys, <
3016             SA0 8 1
3017             Lz4 1 2->3
3018             Ld3 2 3->5
3019             Rz4 1 4->3
3020             Ld2 3 5->9
3021             Lz4 1 6->7
3022             Rd3 2 7->5
3023             Rz4 1 8->7
3024             Rd1 7 9->1
3025             Lz5 1 10->11
3026             Ld4 2 11->13
3027             Rz5 1 12->11
3028             Ld3 3 13->17
3029             Lz5 1 14->15
3030             Rd4 2 15->13
3031             Rz5 1 16->15
3032             Rd2 6 17->9
3033             Lz5 1 18->19
3034             Ld4 2 19->21
3035             Rz5 1 20->19
3036             Rd3 5 21->17
3037             Lz5 1 22->23
3038             Rd4 4 23->21
3039             Lz6 1 24->25
3040             Rd5 3 25->23
3041             Lz7 1 26->27
3042             Rd6 2 27->25
3043             Rz7 1 28->27
3044             END
3045             #save $t;
3046              
3047             for my $k(reverse 1..$N)
3048             {$t->delete($k);
3049             is_deeply $t->printKeys, <
3050             SA0 5 1
3051             Lz4 1 2->3
3052             Ld3 2 3->5
3053             Rz4 1 4->3
3054             Ld2 3 5->9
3055             Lz4 1 6->7
3056             Rd3 2 7->5
3057             Rz4 1 8->7
3058             Rd1 4 9->1
3059             Lz4 1 10->11
3060             Ld3 2 11->13
3061             Rz4 1 12->11
3062             Rd2 3 13->9
3063             Lz4 1 14->15
3064             Rd3 2 15->13
3065             Rz4 1 16->15
3066             END
3067             #save $t if $k == 17;
3068              
3069             is_deeply $t->printKeys, <
3070             SA0 4 1
3071             Lz3 1 2->3
3072             Ld2 2 3->5
3073             Rz3 1 4->3
3074             Rd1 3 5->1
3075             Lz3 1 6->7
3076             Rd2 2 7->5
3077             Rz3 1 8->7
3078             END
3079             #save $t if $k == 9;
3080              
3081             is_deeply $t->printKeys, <
3082             SA0 4 1
3083             Lz2 1 2->3
3084             Rd1 3 3->1
3085             Lz3 1 4->5
3086             Rl2 2 5->3
3087             END
3088             #save $t if $k == 6;
3089              
3090             is_deeply $t->printKeys, <
3091             SA0 3 1
3092             Rr1 2 2->1
3093             Rz2 1 3->2
3094             END
3095             #save $t if $k == 4;
3096              
3097             is_deeply $t->printKeys, <
3098             SA0 2 1
3099             Rz1 1 2->1
3100             END
3101             #save $t if $k == 3;
3102              
3103             is_deeply $t->printKeys, <
3104             Sz0 1
3105             END
3106             #save $t if $k == 1;
3107             }
3108             }
3109              
3110             if (1) #TsetKeysPerNode #Tname
3111             {lll "Split and Refill";
3112             my $N = 22;
3113             my $t = Tree::Bulk::new;
3114             for my $k(1..$N)
3115             {$t->insert($k, 2 * $k);
3116             }
3117              
3118             is_deeply $t->name, "1 2 3 4";
3119              
3120             is_deeply $t->printKeys, <
3121             SA0 4 1 2 3 4
3122             Lz2 1 5 6 7 8->9 10 11 12
3123             Rd1 3 9 10 11 12->1 2 3 4
3124             Lz3 1 13 14 15 16->17 18 19 20
3125             Rd2 2 17 18 19 20->9 10 11 12
3126             Rz3 1 21 22->17 18 19 20
3127             END
3128             #save $t;
3129              
3130             for my $n($t->inorder)
3131             {$n->setKeysPerNode(2);
3132             }
3133             is_deeply $t->printKeys, <
3134             SA0 5 1 2
3135             Lz3 1 3 4->5 6
3136             Ld2 2 5 6->9 10
3137             Rz3 1 7 8->5 6
3138             Rd1 4 9 10->1 2
3139             Lz4 1 11 12->13 14
3140             Ld3 2 13 14->17 18
3141             Rz4 1 15 16->13 14
3142             Rd2 3 17 18->9 10
3143             Rr3 2 19 20->17 18
3144             Rz4 1 21 22->19 20
3145             END
3146             #save $t;
3147              
3148             for my $n($t->inorder)
3149             {$n->setKeysPerNode(1);
3150             }
3151             is_deeply $t->printKeys, <
3152             SA0 6 1
3153             Lz4 1 2->3
3154             Ld3 2 3->5
3155             Rz4 1 4->3
3156             Ld2 3 5->9
3157             Lz4 1 6->7
3158             Rd3 2 7->5
3159             Rz4 1 8->7
3160             Rd1 5 9->1
3161             Lz5 1 10->11
3162             Ld4 2 11->13
3163             Rz5 1 12->11
3164             Ld3 3 13->17
3165             Lz5 1 14->15
3166             Rd4 2 15->13
3167             Rz5 1 16->15
3168             Rd2 4 17->9
3169             Lz4 1 18->19
3170             Rd3 3 19->17
3171             Lz5 1 20->21
3172             Rd4 2 21->19
3173             Rz5 1 22->21
3174             END
3175             #save $t;
3176              
3177             $_->setKeysPerNode(2) for $t->inorder;
3178             is_deeply $t->printKeys, <
3179             SA0 5 1 2
3180             Lz3 1 3 4->5 6
3181             Ld2 2 5 6->9 10
3182             Rz3 1 7 8->5 6
3183             Rd1 4 9 10->1 2
3184             Lz4 1 11 12->13 14
3185             Ld3 2 13 14->17 18
3186             Rz4 1 15 16->13 14
3187             Rd2 3 17 18->9 10
3188             Lz4 1 19 20->21 22
3189             Rl3 2 21 22->17 18
3190             END
3191             #save $t;
3192              
3193             $_->setKeysPerNode(4) for $t->inorder;
3194             is_deeply $t->printKeys, <
3195             SA0 4 1 2 3 4
3196             Lz2 1 5 6 7 8->9 10 11 12
3197             Rd1 3 9 10 11 12->1 2 3 4
3198             Lz3 1 13 14 15 16->17 18 19 20
3199             Rd2 2 17 18 19 20->9 10 11 12
3200             Rz3 1 21 22->17 18 19 20
3201             END
3202             #save $t;
3203             }
3204              
3205             if (1) #TactualHeight #TprintKeysAndData
3206             {my $N = 22;
3207             my $t = Tree::Bulk::new;
3208             ok $t->empty;
3209             ok $t->leaf;
3210              
3211             for(1..$N)
3212             {$t->insert($_, 2 * $_);
3213             }
3214              
3215             ok $t->right->duplex;
3216             is_deeply actualHeight($t), 4;
3217              
3218             is_deeply $t->printKeys, <
3219             SA0 4 1 2 3 4
3220             Lz2 1 5 6 7 8->9 10 11 12
3221             Rd1 3 9 10 11 12->1 2 3 4
3222             Lz3 1 13 14 15 16->17 18 19 20
3223             Rd2 2 17 18 19 20->9 10 11 12
3224             Rz3 1 21 22->17 18 19 20
3225             END
3226             #save $t;
3227              
3228             is_deeply $t->printKeysAndData, <
3229             1 2
3230             2 4
3231             3 6
3232             4 8
3233             5 10
3234             6 12
3235             7 14
3236             8 16
3237             9 18
3238             10 20
3239             11 22
3240             12 24
3241             13 26
3242             14 28
3243             15 30
3244             16 32
3245             17 34
3246             18 36
3247             19 38
3248             20 40
3249             21 42
3250             22 44
3251             END
3252              
3253             my %t = map {$_=>2*$_} 1..$N;
3254              
3255             for(map {2 * $_} 1..$N/2)
3256             {$t->delete($_);
3257             delete $t{$_};
3258             checkAgainstHash $t, %t;
3259             }
3260              
3261             is_deeply $t->printKeys, <
3262             SA0 3 1 3 5 7
3263             Rr1 2 9 11 13 15->1 3 5 7
3264             Rz2 1 17 19 21->9 11 13 15
3265             END
3266             #save($t);
3267              
3268             is_deeply $t->printKeysAndData, <
3269             1 2
3270             3 6
3271             5 10
3272             7 14
3273             9 18
3274             11 22
3275             13 26
3276             15 30
3277             17 34
3278             19 38
3279             21 42
3280             END
3281              
3282             for(map {2 * $_-1} 1..$N/2)
3283             {$t->delete($_);
3284             delete $t{$_};
3285             checkAgainstHash $t, %t;
3286             }
3287              
3288             is_deeply $t->printKeys, <
3289             Sz0 1
3290             END
3291             #save($t);
3292             }
3293              
3294             if (1)
3295             {my $N = 230;
3296             my $t = Tree::Bulk::new;
3297              
3298             for(reverse 1..$N)
3299             {$t->insert($_, 2 * $_);
3300             }
3301             for(reverse 1..$N)
3302             {$t->delete($_);
3303             }
3304             is_deeply $t->printKeys, <
3305             Sz0 1
3306             END
3307             #save $t;
3308              
3309             }
3310              
3311             if (1) #Tfirst #Tnext #Tinorder #Tlast #Tprev
3312             {my $N = 220;
3313             my $t = Tree::Bulk::new;
3314              
3315             for(reverse 1..$N)
3316             {$t->insert($_, 2*$_);
3317             }
3318              
3319             is_deeply $t->actualHeight, 10;
3320              
3321             if (1)
3322             {my @n;
3323             for (my $n = $t->first; $n; $n = $n->next)
3324             {push @n, $n->keys->@*
3325             }
3326             is_deeply \@n, [1..$N];
3327             }
3328              
3329             if (1)
3330             {my @p;
3331             for my $p(reverse $t->inorder)
3332             {push @p, reverse $p->keys->@*;
3333             }
3334             is_deeply \@p, [reverse 1..$N];
3335             }
3336              
3337             my @p;
3338             for(my $p = $t->last; $p; $p = $p->prev)
3339             {push @p, reverse $p->keys->@*
3340             }
3341             is_deeply \@p, [reverse 1..$N];
3342              
3343             my %t = map {$_=>2*$_} 1..$N;
3344             for my $i(0..3)
3345             {for my $j(map {4 * $_-$i} 1..$N/4)
3346             {$t->delete ($j);
3347             delete $t{$j};
3348             checkAgainstHash $t, %t;
3349             }
3350             }
3351              
3352             ok $t->empty;
3353             is_deeply $t->actualHeight, 1;
3354             }
3355              
3356             if (1) #Tnames
3357             {my sub randomLoad($$$) # Randomly load different size nodes
3358             {my ($N, $keys, $height) = @_; # Number of elements, number of keys per node, expected height
3359              
3360             lll "Random load $keys";
3361              
3362             srand(1); # Same randomization
3363             my $t = Tree::Bulk::new->setKeysPerNode($keys);
3364             for my $r(randomizeArray 1..$N)
3365             {$debug = $r == 74;
3366             $t->insert($r, 2 * $r);
3367             $t->check;
3368             }
3369              
3370             is_deeply $t->actualHeight, $height; # Check height
3371             confess unless $t->actualHeight == $height;
3372             is_deeply join(' ', 1..$N), $t->names;
3373              
3374             my %t = map {$_=>2*$_} 1..$N;
3375             for my $r(randomizeArray 1..$N) # Delete in random order
3376             {$t->delete ($r);
3377             delete $t{$r};
3378             checkAgainstHash $t, %t;
3379             check($t);
3380             }
3381              
3382             ok $t->empty;
3383             is_deeply $t->actualHeight, 1;
3384             }
3385              
3386             randomLoad(222, 1, 11);
3387             randomLoad(222, 8, 8);
3388             randomLoad(222, 4, 9);
3389             }
3390              
3391             if (1) #Tfind
3392             {my $t = Tree::Bulk::new;
3393             $t->insert($_, $_*$_) for 1..20;
3394             ok !find($t, 0);
3395             ok !find($t, 21);
3396             ok find($t, $_) == $_ * $_ for qw(1 5 10 11 15 20);
3397             }
3398              
3399             lll "Success:", time - $start;