File Coverage

blib/lib/Tree/Bulk.pm
Criterion Covered Total %
statement 329 343 95.9
branch 218 296 73.6
condition 78 104 75.0
subroutine 57 59 96.6
pod 39 44 88.6
total 721 846 85.2


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 = "20210302";
9 1     1   885 use warnings FATAL => qw(all);
  1         8  
  1         38  
10 1     1   6 use strict;
  1         2  
  1         35  
11 1     1   7 use Carp qw(confess cluck);
  1         3  
  1         97  
12 1     1   653 use Data::Dump qw(dump);
  1         8208  
  1         112  
13 1     1   4468 use Data::Table::Text qw(:all);
  1         151658  
  1         1943  
14 1     1   13 use feature qw(say current_sub);
  1         2  
  1         6298  
15              
16             sub saveLog($) #P Save a result to the log file if we are developing
17 0     0 0 0 {my ($string) = @_; # String to save
18 0         0 my $l = q(/home/phil/perl/z/bulkTree/zzz.txt); # Log file if available
19              
20 0 0       0 owf($l, $string) if -e $l;
21 0         0 confess "Saved to logfile:\n$l\n";
22             exit
23 0         0 }
24              
25             sub save # Simplified save
26 0     0 0 0 {my ($t) = @_; # Tree
27 0         0 saveLog($t->printKeys);
28             }
29              
30 74428     74428 0 377548 sub Left {q(left)} # Left
31 74370     74370 0 315315 sub Right {q(right)} # Right
32              
33             #D1 Bulk Tree # Bulk Tree
34              
35             sub node(;$$$$) #P Create a new bulk tree node
36 562     562 1 1835 {my ($key, $data, $up, $side) = @_; # Key, $data, parent node, side of parent node
37 562 100       10006 my $t = genHash(__PACKAGE__, # Bulk tree node
    100          
    100          
38             keysPerNode => $up ? $up->keysPerNode : 4, # Maximum number of keys per node
39             up => $up, # Parent node
40             left => undef, # Left node
41             right => undef, # Right node
42             height => 1, # Height of node
43             keys => [$key ? $key : ()], # Array of data items for this node
44             data => [$data ? $data : ()], # Data corresponding to each key
45             );
46              
47 562 100       63672 if ($up) # Install new node in tree
48 518 50       1315 {if ($side)
49 518         1172 {$up->{$side} = $t;
50 518         2598 $up->setHeights(2);
51             }
52             else
53 0 0       0 {confess 'Specify side' if !$side;
54             }
55             }
56             $t
57 562         22041 }
58              
59 14     14 1 48 sub new {node} # Create a new tree
60              
61             sub isRoot($) # Return the tree if it is the root
62 116664     116664 1 519301 {my ($tree) = @_; # Tree
63 116664 50       186862 confess unless $tree;
64 116664 100       1692312 !$tree->up ? $tree : undef
65             }
66              
67             sub root($) # Return the root node of a tree
68 1334     1334 1 3240 {my ($tree) = @_; # Tree
69 1334 50       3605 confess unless $tree;
70 1334         23003 for(; $tree->up; $tree = $tree->up) {}
71 1334         13568 $tree
72             }
73              
74             sub leaf($) # Return the tree if it is a leaf
75 93847     93847 1 329995 {my ($tree) = @_; # Tree
76 93847 50       153540 confess unless $tree;
77 93847 100 66     1398685 $tree and !$tree->right and !$tree->left ? $tree : undef
    100          
78             }
79              
80             sub duplex($) # Return the tree if it has left and right children
81 489     489 1 1055 {my ($tree) = @_; # Tree
82 489 50       1144 confess unless $tree;
83 489 100       7614 $tree->right and $tree->left ? $tree : undef
    100          
84             }
85              
86             sub simplex($) # Return the tree if it has either a left child or a right child but not both.
87 73696     73696 1 120663 {my ($tree) = @_; # Tree
88 73696 50       131726 confess unless $tree;
89 73696 100 100     1077076 $tree->right xor $tree->left ? $tree : undef
90             }
91              
92             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.
93 9460     9460 1 215282 {my ($tree) = @_; # Tree
94 9460 50       21366 confess unless $tree;
95 9460 50 50     142342 return undef unless $tree->right xor $tree->left;
96 9460 100 100     312443 return undef if $tree->right and !$tree->right->leaf;
97 9429 100 100     248389 return undef if $tree->left and !$tree->left ->leaf;
98 9421         140271 $tree
99             }
100              
101             sub empty($) # Return the tree if it is empty
102 3442     3442 1 6115 {my ($tree) = @_; # Tree
103 3442 50       7118 confess unless $tree;
104 3442 100       6398 $tree->leaf and !$tree->keys->@* ? $tree : undef
    100          
105             }
106              
107             sub singleton($) # Return the tree if it contains only the root node and nothing else
108 4378     4378 1 6644 {my ($tree) = @_; # Tree
109 4378 50       7531 confess unless $tree;
110 4378 100       9851 $tree->leaf and $tree->isRoot ? $tree : undef;
    100          
111             }
112              
113             sub isLeftChild($) # Return the tree if it is the left child
114 726     726 1 1684 {my ($tree) = @_; # Tree
115 726 50       1592 confess unless $tree;
116 726 100 66     11330 $tree->up and $tree->up->left and $tree->up->left == $tree ? $tree : undef;
    100          
117             }
118              
119             sub isRightChild($) # Return the tree if it is the right child
120 170     170 1 349 {my ($tree) = @_; # Tree
121 170 50       364 confess unless $tree;
122 170 100 66     2672 $tree->up and $tree->up->right and $tree->up->right == $tree ? $tree : undef;
    100          
123             }
124              
125             sub name($) # Name of a tree
126 74474     74474 1 99317 {my ($tree) = @_; # Tree
127 74474 50       105158 confess unless $tree;
128 74474         1084186 join ' ', $tree->keys->@*
129             }
130              
131             sub names($) # Names of all nodes in a tree in order
132 3     3 1 10 {my ($tree) = @_; # Tree
133 3 50       9 confess unless $tree;
134 3         18 join ' ', map {$_->name} $tree->inorder;
  329         1803  
135             }
136              
137             sub setHeights($) #P Set heights along path to root
138 1011     1011 1 4011 {my ($tree) = @_; # Tree
139 1011 50       3424 confess unless $tree;
140 1011         3036 for(my $n = $tree; $n; $n = $n->up)
141 6257         30727 {$n->setHeight;
142 6257         27281 $n->balance;
143             }
144             } # setHeights
145              
146             sub actualHeight($) #P Get the height of a node
147 30182     30182 1 202829 {my ($tree) = @_; # Tree
148 30182 100       72438 return 0 unless $tree;
149 24288         355872 $tree->height
150             }
151              
152             sub maximum($$) #P Maximum of two numbers
153 7474     7474 1 13130 {my ($a, $b) = @_; # First, second
154 7474 100       117337 $a > $b ? $a : $b
155             }
156              
157             sub setHeight($) #P Set height of a tree from its left and right trees
158 7472     7472 1 15374 {my ($tree) = @_; # Tree
159 7472 50       13145 confess unless $tree;
160 7472         113332 my $l = actualHeight($tree->left);
161 7472         124510 my $r = actualHeight($tree->right);
162 7472         27181 $tree->height = 1 + maximum($l, $r);
163             } # setHeight
164              
165             # Rotate left
166              
167             # p p
168             # n r
169             # l r n R
170             # L R l L
171              
172             sub rotateLeft($) #P Rotate a node left
173 487     487 1 1573 {my ($n) = @_; # Node
174 487 50       1068 confess unless $n;
175 487         7416 my $p = $n->up;
176 487 100       2365 return unless $p;
177 169         2626 my $r = $n->right;
178 169 100       865 return unless $r;
179 168         2597 my $L = $r->left;
180 168 100       1154 $p->{$n->isRightChild ? Right : Left} = $r; $r->up = $p;
  168         2748  
181 168         2994 $r->left = $n; $n->up = $r;
  168         2994  
182 168 100       2979 $n->right = $L; $L->up = $n if $L;
  168         1410  
183 168         697 setHeight $_ for $n, $r, $p;
184 168         1197 $r->refill;
185             } # rotateLeft
186              
187             sub rotateRight($) #P Rotate a node right
188 467     467 1 1015 {my ($n) = @_; # Node
189 467 50       1154 confess unless $n;
190 467         7485 my $p = $n->up;
191 467 100       2476 return unless $p;
192 238         3657 my $l = $n->left;
193 238 100       1173 return unless $l;
194 237         3643 my $R = $l->right;
195 237 100       1642 $p->{$n->isLeftChild ? Left : Right} = $l; $l->up = $p;
  237         3816  
196 237         4419 $l->right = $n; $n->up = $l;
  237         4595  
197 237 100       4336 $n->left = $R; $R->up = $n if $R;
  237         2540  
198 237         1001 setHeight $_ for $n, $l, $p;
199 237         2141 $l->refill;
200             } # rotateLeft
201              
202             # Balance - make the deepest sub tree one less deep
203              
204             # 1 1
205             # 2 5
206             # 6 2 6
207             # 5 4
208             # 4 3
209             # 3
210              
211             sub balance($) # Balance a node
212 6751     6751 1 12798 {my ($t) = @_; # Tree
213 6751 50       11806 confess unless $t;
214 6751         100829 my ($l, $r) = (actualHeight($t->left), actualHeight($t->right));
215              
216 6751 100       33117 if ($l > 2 * $r + 1) # Rotate right
    100          
217 425 50       6990 {if (my $l = $t->left) # Counter balance if necessary
218 425 100       8210 {if (actualHeight($l->right) > actualHeight($l->left))
219 48         285 {$l->rotateLeft
220             }
221             }
222 425         3856 $t->rotateRight;
223             }
224             elsif ($r > 2 * $l + 1) # Rotate left
225 437 50       6681 {if (my $r = $t->right) # Counter balance if necessary
226 437 100       7833 {if (actualHeight($r->left) > actualHeight($r->right))
227 40         194 {$r->rotateRight
228             }
229             }
230 437         3611 $t->rotateLeft;
231             }
232              
233             $t
234 6751         103458 } # balance
235              
236             sub insertUnchecked($$$) #P Insert a key and some data into a tree
237             {my ($tree, $key, $data) = @_; # Tree, key, data
238             confess unless $tree;
239             confess unless defined $key;
240              
241             my sub insertIntoNode # Insert the current key into the specified node
242             {my @k; my @d; # Rebuilt node
243             my $low = 1; # Keys less than the key
244             for my $i(keys $tree->keys->@*) # Insert key and data in node
245             {my $k = $tree->keys->[$i];
246             confess "Duplicate key" if $k == $key;
247             if ($low and $k > $key) # Insert key and data before first greater key
248             {$low = undef;
249             push @k, $key;
250             push @d, $data;
251             }
252             push @k, $k;
253             push @d, $tree->data->[$i];
254             }
255             if ($low) # Key bigger than largest key
256             {push @d, $data;
257             push @k, $key;
258             }
259             $tree->keys = \@k; $tree->data = \@d; # Keys and data in node
260             } # insertIntoNode
261              
262             if ($tree->keys->@* < $tree->keysPerNode and leaf $tree) # Small node so we can add within the node
263             {insertIntoNode;
264             return $tree;
265             }
266              
267             elsif ($key < $tree->keys->[0]) # Less than least - Go left
268             {if ($tree->left) # New node left
269             {return __SUB__->($tree->left, $key, $data);
270             }
271             else
272             {return node $key, $data, $tree, Left; # Add a new node left
273             }
274             }
275              
276             elsif ($key > $tree->keys->[-1]) # Greater than most - go right
277             {if ($tree->right) # New node right
278             {return __SUB__->($tree->right, $key, $data);
279             }
280             else
281             {return node $key, $data, $tree, Right; # Add a new node right
282             }
283             }
284              
285             else # Full node and key is inside it
286             {insertIntoNode; # Keys in node
287             if ($tree->keys->@* > $tree->keysPerNode) # Reinsert last key and data if the node is now to big
288             {my $k = pop $tree->keys->@*;
289             my $d = pop $tree->data->@*;
290             if (my $r = $tree->right)
291             {return $r->insertUnchecked($k, $d);
292             }
293             else # Insert right in new node and balance
294             {return node $k, $d, $tree, Right;
295             }
296             }
297             return $tree;
298             }
299             } # insertUnchecked
300              
301             sub insert($$$) # Insert a key and some data into a tree
302 1234     1234 1 3458 {my ($tree, $key, $data) = @_; # Tree, key, data
303 1234 50       3021 confess unless $tree;
304 1234 50       2644 confess unless defined $key;
305 1234         9588 $tree->insertUnchecked($key, $data);
306             } # insert
307              
308             sub find($$) # Find a key in a tree and returns its data
309 97922     97922 1 164573 {my ($tree, $key) = @_; # Tree, key
310 97922 50       156541 confess unless $tree;
311 97922 50       144601 confess "No key" unless defined $key;
312 97922 50       251202 confess "Non numeric key" unless $key =~ m(\A\d+\Z);
313              
314             sub # Find the key in the sub-tree
315 515873     515873   2270801 {my ($tree) = @_; # Sub-tree
316 515873 100       851304 if ($tree)
317 515871         7668094 {my $keys = $tree->keys;
318 515871 50       2066903 confess "Empty node" unless $keys->@*;
319              
320 515871 100       3600966 return __SUB__->($tree->left) if $key < $$keys[ 0];
321 323276 100       3538319 return __SUB__->($tree->right) if $key > $$keys[-1];
322              
323 97920         181484 for my $i(keys $keys->@*) # Find key in node
324 237672         3467387 {my $v = $tree->data->[$i];
325 237672 50       972892 confess "undefined data for key $key" unless defined $v;
326 237672 100       1732215 return $tree->data->[$i] if $key == $$keys[$i];
327             }
328             }
329             undef
330 97922         390330 }->($tree)
  2         12  
331             } # find
332              
333             sub first($) # First node in a tree
334 356     356 1 7885 {my ($n) = @_; # Tree
335 356 50       1114 confess unless $n;
336 356         5535 $n = $n->left while $n->left;
337 356         7626 $n
338             }
339              
340             sub last($) # Last node in a tree
341 412     412 1 9651 {my ($n) = @_; # Tree
342 412 50       1105 confess unless $n;
343 412         6490 $n = $n->right while $n->right;
344 412         10204 $n
345             }
346              
347             sub next($) # Next node in order
348 1079     1079 1 2424 {my ($tree) = @_; # Tree
349 1079 50       2328 confess unless $tree;
350 1079 100       16627 if (my $r = $tree->right)
351 830 100       15110 {return $r->left ? $r->left->first : $r;
352             }
353 249         985 my $p = $tree;
354 249         450 for(; $p; $p = $p->up)
355 489 100 100     27836 {return $p->up unless $p->up and $p->up->right and $p->up->right == $p;
      100        
356             }
357             undef
358 0         0 }
359              
360             sub prev($) # Previous node in order
361 827     827 1 1984 {my ($tree) = @_; # Tree
362 827 50       1693 confess unless $tree;
363 827 100       12718 if (my $l = $tree->left)
364 800 100       15564 {return $l->right ? $l->right->last : $l;
365             }
366 27         104 my $p = $tree;
367 27         49 for(; $p; $p = $p->up)
368 55 100 66     3152 {return $p->up unless $p->up and $p->up->left and $p->up->left == $p;
      100        
369             }
370             undef
371 0         0 }
372              
373             sub inorder($) # Return a list of all the nodes in a tree in order
374 8     8 1 26 {my ($tree) = @_; # Tree
375 8 50       25 confess unless $tree;
376 8         18 my @n;
377 8         30 for(my $n = $tree->first; $n; $n = $n->next)
378 434         18924 {push @n, $n;
379             }
380             @n
381 8         345 }
382              
383             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
384 487     487 1 15568 {my ($t) = @_; # Tree
385 487 50       1308 confess unless $t;
386 487 50       1448 confess "Duplex tree cannot be unchained" if duplex $t;
387 487 50       9660 confess "Root cannot be unchained" unless my $p = $t->up;
388              
389 487   66     9138 my $c = $t->left // $t->right; # Not duplex so at most one of these
390 487 100       11201 $p->{$t->isLeftChild ? Left : Right} = $c; # Unchain
391 487 100       1176 $c->up = $p if $c;
392 487         7976 $t->up = undef;
393              
394 487 100       8061 if (my $l = $p->left) {$l->setHeights($l->height)} # Set heights from a known point
  129 100       2536  
395 129         4729 elsif (my $r = $p->right) {$r->setHeights($r->height)}
396 229         5737 else {$p->setHeights(1)}
397              
398 487         3558 $p->balance; # Rebalance parent
399              
400 487         4390 $p # Unchained node
401             } # unchain
402              
403             sub refillFromRight($) #P Push a key to the target node from the next node
404 590     590 1 5406 {my ($target) = @_; # Target tree
405              
406 590 50       1953 confess unless $target;
407 590 50       9126 confess "No right" unless $target->right; # Ensure source will be in this sub tree
408 590 50       4423 confess "No source" unless my $source = $target->next; # No source
409              
410 590   100     11047 while ($source->keys->@* > 0 and $target->keys->@* < $target->keysPerNode) # Transfer fill from source
411 595         31504 {push $target->keys->@*, shift $source->keys->@*;
412 595         12134 push $target->data->@*, shift $source->data->@*;
413             }
414 590 100       24875 $source->unchain if $source->empty;
415 590         15737 $_->refill for $target, $source;
416             } # refillFromRight
417              
418             sub refillFromLeft($) #P Push a key to the target node from the previous node
419 772     772 1 5832 {my ($target) = @_; # Target tree
420              
421 772 50       2194 confess unless $target;
422 772 50       11762 confess "No left" unless $target->left; # Ensure source will be in this sub tree
423 772 50       5186 confess "No source" unless my $source = $target->prev; # No source
424              
425 772   100     13864 while ($source->keys->@* > 0 and $target->keys->@* < $target->keysPerNode) # Transfer fill from source
426 418         22541 {unshift $target->keys->@*, pop $source->keys->@*;
427 418         8957 unshift $target->data->@*, pop $source->data->@*;
428             }
429              
430 772 100       34976 $source->unchain if $source->empty;
431 772         27025 $_->refill for $target, $source;
432             } # refillFromLeft
433              
434             sub refill($) #P Refill a node so it has the expected number of keys
435 4377     4377 1 34233 {my ($tree) = @_; # Tree
436 4377 50       8939 confess unless $tree;
437 4377 100       10044 return if $tree->singleton;
438 3984 100       97726 return if $tree->keys->@* == $tree->keysPerNode;
439              
440 2074 100       46846 if ($tree->empty) # Remove an empty leaf that is not the root
    100          
441 171 50       7097 {$tree->unchain unless $tree->isRoot;
442             }
443              
444             elsif ($tree->keys->@* < $tree->keysPerNode) # Refill the node from neighboring leaf nodes
445 1886 100       110812 {if (!$tree->leaf) # Do not refill leaves
446 982 100       26510 {$tree->refillFromRight if $tree->right;
447 982 100       25720 $tree->refillFromLeft if $tree->left;
448             }
449             }
450              
451             else
452 17         1147 {while($tree->keys->@* > $tree->keysPerNode) # Empty node if over full
453 25         856 {$tree->insertUnchecked(pop $tree->keys->@*, pop $tree->data->@*); # Reinsert lower down
454             }
455             }
456             } # refill
457              
458             sub delete($$) # Delete a key in a tree
459 1167     1167 1 3511 {my ($tree, $key) = @_; # Tree, key
460 1167 50       4355 confess unless $tree;
461 1167 50       3419 confess "No key" unless defined $key;
462              
463             sub # Find then delete the key in the sub-tree
464 4661     4661   24922 {my ($tree) = @_; # Sub-tree
465 4661 50       8578 return unless $tree;
466 4661 50       71315 return unless $tree->keys->@*; # Empty tree
467 4661 100       85152 if ($key < $tree->keys->[ 0]) {__SUB__->($tree->left)} # Less than least key so go left
  1653 100       30855  
    50          
468 1841         63392 elsif ($key > $tree->keys->[-1]) {__SUB__->($tree->right)} # Greater than most key so go right
469 4201         51822 elsif (grep {$_ == $key} $tree->keys->@*) # Key present in current node
470 1167         2295 {my @k, my @d;
471 1167         18139 for my $i(keys $tree->keys->@*) # Remove the key and corresponding data
472 4201 100       74648 {next if $tree->keys->[$i] == $key;
473 3034         54122 push @d, $tree->data->[$i];
474 3034         53033 push @k, $tree->keys->[$i];
475             }
476 1167         22623 $tree->keys = \@k; $tree->data = \@d;
  1167         22181  
477 1167         8588 $tree->refill; # Refill the tree
478             }
479 1167         9668 }->($tree);
480             } # delete
481              
482             sub printKeys2($$$) #P print the keys for a tree
483 522     522 1 2184 {my ($t, $in, $g) = @_; # Tree, indentation, list of keys,
484 522 100       991 return unless $t;
485 243         3844 __SUB__->($t->left, $in+1, $g); # Left
486              
487 243         3837 my $h = $t->height;
488 243 100 100     4187 my $s = $t->up && $t->up->left && $t->up->left == $t ? 'L' : # Print
    100 66        
489             $t->up && $t->up->right && $t->up->right == $t ? 'R' : 'S';
490 243 100 100     25213 $s .= $t->leaf ? 'z' : $t->isRoot ? 'A' : $t->left && $t->right ? 'd' : $t->left ? 'l' : 'r';
    100          
    100          
    100          
491 243         7160 $s .= "$in $h ".(' ' x $in);
492 243         497 $s .= $t->name;
493 243 100       4700 $s .= '->'.$t->up->name if $t->up;
494 243         1377 push @$g, $s;
495              
496 243         3761 __SUB__->($t->right, $in+1, $g); # Right
497             }
498              
499             sub printKeys($) # Print the keys in a tree
500 36     36 1 69 {my ($t) = @_; # Tree
501 36 50       101 confess unless $t;
502              
503 36         59 my @s;
504 36         97 printKeys2 $t, 0, \@s;
505              
506 36         568 (join "\n", @s, "") =~ s(\s+\Z) (\n)sr
507             } # printKeys
508              
509             sub setKeysPerNode($$) # Set the number of keys for the current node
510 81     81 1 174 {my ($tree, $N) = @_; # Tree, keys per node to be set
511 81 50       158 confess unless $tree;
512 81 50 33     307 confess unless $N and $N > 0;
513 81         1430 $tree->keysPerNode = $N; # Set
514 81         413 $tree->refill; # Refill if necessary
515 81         2106 $tree # Allow chaining
516             } # setKeysPerNode
517              
518             sub printKeysAndData($) # Print the mapping from keys to data in a tree
519             {my ($t) = @_; # Tree
520             confess unless $t;
521             my @s;
522             my sub print($$)
523             {my ($t, $in) = @_;
524             return unless $t;
525             __SUB__->($t->left, $in+1); # Left
526             push @s, [$t->keys->[$_], $t->data->[$_]] for keys $t->keys->@*; # Find key in node
527             __SUB__->($t->right, $in+1); # Right
528             }
529             print $t, 0;
530             formatTableBasic(\@s)
531             } # printKeysAndData
532              
533             sub checkLRU($) #P Confirm pointers in tree
534 1332     1332 1 2979 {my ($tree) = @_; # Tree
535 1332         2179 my %seen; # Nodes we have already seen
536              
537             sub # Check pointers in a tree
538 148720     148720   218448 {my ($tree, $dir) = @_; # Tree
539 148720 100       260649 return unless $tree;
540              
541 73694 50       115969 confess "Recursed $dir into: ".$tree->name if $seen{$tree->name}++;
542              
543 73694         1447370 __SUB__->($tree->left, Left);
544 73694         1066813 __SUB__->($tree->right, Right);
545 1332         5576 }->($tree->root);
546             }
547              
548             sub check($) #P Confirm that each node in a tree is ordered correctly
549 1332     1332 1 4467 {my ($tree) = @_; # Tree
550 1332 50       4221 confess unless $tree;
551 1332         5608 $tree->checkLRU;
552              
553 1332         26211 my $maxHeight = 0;
554              
555             sub
556 148720     148720   655702 {my ($tree) = @_; # Tree
557 148720 100       256310 return unless $tree;
558              
559 73694         1050704 __SUB__->($tree->left);
560 73694         1098534 __SUB__->($tree->right);
561              
562 73694 50       1116860 confess $tree->name unless $tree->keys->@* == $tree->data->@*; # Check key count matches data count
563              
564 73694 50 100     1510198 if ( !$tree->leaf and !$tree->isRoot # Confirm that all interior nodes are fully filled
      66        
565             and $tree->keys->@* != $tree->keysPerNode)
566 0         0 {confess "Interior node not full: "
567             .$tree->name."\n". $tree->root->printKeys;
568             }
569              
570 73694 50 66     2251274 confess $tree->name unless $tree->isRoot or # Node is either a root or a left or right child
      100        
      100        
      33        
      33        
      66        
571             $tree->up && $tree->up->left && $tree == $tree->up->left or
572             $tree->up && $tree->up->right && $tree == $tree->up->right;
573              
574 73694 50 33     9463861 confess 'Left:'.$tree->name if $tree->left and # Left child has correct parent
      66        
575             !$tree->left->up || $tree->left->up != $tree;
576              
577 73694 50 33     3421118 confess 'Right:'.$tree->name if $tree->right and # Right child has correct parent
      66        
578             !$tree->right->up || $tree->right->up != $tree;
579              
580 73694 50 100     2498372 if ($tree->simplex and !$tree->simplexWithLeaf and $tree->up # Simplex children must always have duplex parents
      100        
      66        
      33        
581             and !$tree->up->isRoot and !$tree->up->duplex)
582 0         0 {confess "Simplex does not have duplex parent: ".$tree->name
583             ."\n".$tree->root->printKeys;
584             }
585              
586 73694 100       2348819 $maxHeight = $tree->height if $tree->height > $maxHeight;
587              
588 73694         1418848 my @k = $tree->keys->@*; # Check keys
589 73694 50       1374732 @k <= $tree->keysPerNode or confess "Too many keys:".scalar(@k);
590 73694         368967 for my $i(keys @k)
591 147852 50       250433 {confess "undef key position $i" unless defined $k[$i];
592             }
593              
594 73694         1105914 my @d = $tree->data->@*; # Check data
595 73694 50       1297111 @d <= $tree->keysPerNode or confess "Too many data:".scalar(@d);
596              
597 73694         291619 my %k;
598 73694         219815 for my $i(1..$#k)
599 74161 50       127393 {confess "Out of order: ", dump(\@k) if $k[$i-1] >= $k[$i];
600 74161 50       156439 confess "Duplicate key: ", $k[$i] if $k{$k[$i]}++;
601 74161 50       157355 confess "Undefined data: ", $k[$i] unless defined $d[$i];
602             }
603 1332         11837 }->($tree);
604              
605 1332 50       85934 if ($tree->height < $maxHeight) # Check tree heights
606 0         0 {cluck "Tree height failure at: ", $tree->name;
607 0         0 save($tree);
608             }
609             } # check
610              
611             sub checkAgainstHash($%) #P Check a tree against a hash
612 908     908 1 28579 {my ($t, %t) = @_; # Tree, expected
613              
614 908         13068 for my $k(keys %t) # Check we can find all the keys expected
615 97914         208999 {my ($t) = @_;
616 97914         159355 my $v = $t{$k};
617 97914 50       163210 confess "Cannot find $k" unless my $f = find($t, $k);
618 97914 50       1065968 confess "Found $f but expected $v" unless $f == $v;
619             }
620              
621             sub # Check that the tree does not contain unexpected keys
622 88474     88474   333254 {my ($t) = @_;
623 88474 100       151476 return unless $t;
624              
625 43783         610354 __SUB__->($t->left); # Left
626 43783         619501 for($t->keys->@*)
627 97914 50       335310 {confess $_ unless delete $t{$_};
628             }
629 43783         615400 __SUB__->($t->right); # Right
630 908         18177 }->($t);
631              
632 908 50       29797 confess if keys %t; # They should have all been deleted
633             } # checkAgainstHash
634             #d
635             #-------------------------------------------------------------------------------
636             # Export - eeee
637             #-------------------------------------------------------------------------------
638              
639 1     1   12 use Exporter qw(import);
  1         3  
  1         43  
640              
641 1     1   7 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         7  
  1         538  
642              
643             @ISA = qw(Exporter);
644             @EXPORT = qw();
645             @EXPORT_OK = qw(
646             );
647             %EXPORT_TAGS = (all=>[@EXPORT, @EXPORT_OK]);
648              
649             # podDocumentation
650             =pod
651              
652             =encoding utf-8
653              
654             =head1 Name
655              
656             Tree::Bulk - Bulk Tree operations
657              
658             =head1 Synopsis
659              
660             Bulk trees store several (key,data) pairs in each node of a balanced tree to
661             reduce the number of tree pointers: up, left, right, etc. used to maintain the
662             tree. This has no useful effect in Perl code, but in C code, especially C code
663             that uses SIMD instructions, the savings in space can be considerable which
664             allows the processor caches to be used more effectively. This module
665             demonstrates insert, find, delete operations on bulk trees as a basis for
666             coding these algorithms more efficiently in assembler code.
667              
668             is_deeply $t->printKeys, <
669             SA0 4 1 2 3 4
670             Lz2 1 5 6 7 8->9 10 11 12
671             Rd1 3 9 10 11 12->1 2 3 4
672             Lz3 1 13 14 15 16->17 18 19 20
673             Rd2 2 17 18 19 20->9 10 11 12
674             Rz3 1 21 22->17 18 19 20
675             END
676              
677             for my $n($t->inorder)
678             {$n->setKeysPerNode(2);
679             }
680              
681             is_deeply $t->printKeys, <
682             SA0 5 1 2
683             Lz3 1 3 4->5 6
684             Ld2 2 5 6->9 10
685             Rz3 1 7 8->5 6
686             Rd1 4 9 10->1 2
687             Lz4 1 11 12->13 14
688             Ld3 2 13 14->17 18
689             Rz4 1 15 16->13 14
690             Rd2 3 17 18->9 10
691             Rr3 2 19 20->17 18
692             Rz4 1 21 22->19 20
693             END
694              
695             =head1 Description
696              
697             Bulk Tree operations
698              
699              
700             Version "20210302".
701              
702              
703             The following sections describe the methods in each functional area of this
704             module. For an alphabetic listing of all methods by name see L.
705              
706              
707              
708             =head1 Bulk Tree
709              
710             Bulk Tree
711              
712             =head2 isRoot($tree)
713              
714             Return the tree if it is the root
715              
716             Parameter Description
717             1 $tree Tree
718              
719             B
720              
721              
722             if (1)
723             {lll "Attributes";
724             my $t = Tree::Bulk::new->setKeysPerNode(1);
725             my $b = $t->insert(2,4);
726             my $a = $t->insert(1,2);
727             my $c = $t->insert(3,6);
728             ok $a->isLeftChild;
729             ok $c->isRightChild;
730             ok !$a->isRightChild;
731             ok !$c->isLeftChild;
732              
733             ok $b->isRoot; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
734              
735              
736             ok !$a->isRoot; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
737              
738              
739             ok !$c->isRoot; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
740              
741             ok $a->leaf;
742             ok $c->leaf;
743             ok $b->duplex;
744             ok $c->root == $b;
745             ok $c->root != $a;
746             }
747              
748              
749             =head2 root($tree)
750              
751             Return the root node of a tree
752              
753             Parameter Description
754             1 $tree Tree
755              
756             B
757              
758              
759             if (1)
760             {lll "Attributes";
761             my $t = Tree::Bulk::new->setKeysPerNode(1);
762             my $b = $t->insert(2,4);
763             my $a = $t->insert(1,2);
764             my $c = $t->insert(3,6);
765             ok $a->isLeftChild;
766             ok $c->isRightChild;
767             ok !$a->isRightChild;
768             ok !$c->isLeftChild;
769             ok $b->isRoot;
770             ok !$a->isRoot;
771             ok !$c->isRoot;
772             ok $a->leaf;
773             ok $c->leaf;
774             ok $b->duplex;
775              
776             ok $c->root == $b; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
777              
778              
779             ok $c->root != $a; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
780              
781             }
782              
783              
784             =head2 leaf($tree)
785              
786             Return the tree if it is a leaf
787              
788             Parameter Description
789             1 $tree Tree
790              
791             B
792              
793              
794             if (1)
795             {lll "Attributes";
796             my $t = Tree::Bulk::new->setKeysPerNode(1);
797             my $b = $t->insert(2,4);
798             my $a = $t->insert(1,2);
799             my $c = $t->insert(3,6);
800             ok $a->isLeftChild;
801             ok $c->isRightChild;
802             ok !$a->isRightChild;
803             ok !$c->isLeftChild;
804             ok $b->isRoot;
805             ok !$a->isRoot;
806             ok !$c->isRoot;
807              
808             ok $a->leaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
809              
810              
811             ok $c->leaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
812              
813             ok $b->duplex;
814             ok $c->root == $b;
815             ok $c->root != $a;
816             }
817              
818              
819             =head2 duplex($tree)
820              
821             Return the tree if it has left and right children
822              
823             Parameter Description
824             1 $tree Tree
825              
826             B
827              
828              
829             if (1)
830             {lll "Attributes";
831             my $t = Tree::Bulk::new->setKeysPerNode(1);
832             my $b = $t->insert(2,4);
833             my $a = $t->insert(1,2);
834             my $c = $t->insert(3,6);
835             ok $a->isLeftChild;
836             ok $c->isRightChild;
837             ok !$a->isRightChild;
838             ok !$c->isLeftChild;
839             ok $b->isRoot;
840             ok !$a->isRoot;
841             ok !$c->isRoot;
842             ok $a->leaf;
843             ok $c->leaf;
844              
845             ok $b->duplex; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
846              
847             ok $c->root == $b;
848             ok $c->root != $a;
849             }
850              
851              
852             =head2 simplex($tree)
853              
854             Return the tree if it has either a left child or a right child but not both.
855              
856             Parameter Description
857             1 $tree Tree
858              
859             B
860              
861              
862             if (1)
863             {lll "SetHeights";
864             my $a = node(1,1)->setKeysPerNode(1);
865             my $b = node(2,2)->setKeysPerNode(1);
866             my $c = node(3,3)->setKeysPerNode(1);
867             my $d = node(4,4)->setKeysPerNode(1);
868             my $e = node(5,5);
869             $a->right = $b; $b->up = $a;
870             $b->right = $c; $c->up = $b;
871             $c->right = $d; $d->up = $c;
872             $d->right = $e; $e->up = $d;
873              
874             is_deeply $a->printKeys, <
875             SA0 1 1
876             Rr1 1 2->1
877             Rr2 1 3->2
878             Rr3 1 4->3
879             Rz4 1 5->4
880             END
881             #save $a;
882              
883             $e->setHeights(1);
884             is_deeply $a->printKeys, <
885             SA0 4 1
886             Rr1 3 2->1
887             Lz3 1 3->4
888             Rd2 2 4->2
889             Rz3 1 5->4
890             END
891             #save $a;
892              
893             ok $b->simplex; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
894              
895              
896             ok !$c->simplex; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
897              
898              
899             $c->balance;
900             is_deeply $a->printKeys, <
901             SA0 4 1
902             Rr1 3 2->1
903             Lz3 1 3->4
904             Rd2 2 4->2
905             Rz3 1 5->4
906             END
907             #save $a;
908              
909             $b->balance;
910             is_deeply $a->printKeys, <
911             SA0 4 1
912             Lr2 2 2->4
913             Rz3 1 3->2
914             Rd1 3 4->1
915             Rz2 1 5->4
916             END
917             #save $a;
918             }
919              
920              
921             =head2 simplexWithLeaf($tree)
922              
923             Return the tree if it has either a left child or a right child but not both and the child it has a leaf.
924              
925             Parameter Description
926             1 $tree Tree
927              
928             B
929              
930              
931             if (1)
932             {lll "Balance";
933             my $a = node(1,1)->setKeysPerNode(1); $a->height = 5;
934             my $b = node(2,2)->setKeysPerNode(1); $b->height = 4;
935             my $c = node(3,3)->setKeysPerNode(1); $c->height = 3;
936             my $d = node(4,4)->setKeysPerNode(1); $d->height = 2;
937             my $e = node(5,5); $e->height = 1;
938             $a->right = $b; $b->up = $a;
939             $b->right = $c; $c->up = $b;
940             $c->right = $d; $d->up = $c;
941             $d->right = $e; $e->up = $d;
942              
943             $e->balance;
944             is_deeply $a->printKeys, <
945             SA0 5 1
946             Rr1 4 2->1
947             Rr2 3 3->2
948             Rr3 2 4->3
949             Rz4 1 5->4
950             END
951             #save $a;
952              
953             ok $d->simplexWithLeaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
954              
955              
956             ok !$c->simplexWithLeaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
957              
958              
959             $d->balance;
960             is_deeply $a->printKeys, <
961             SA0 5 1
962             Rr1 4 2->1
963             Rr2 3 3->2
964             Rr3 2 4->3
965             Rz4 1 5->4
966             END
967             #save $a;
968              
969             $c->balance;
970             is_deeply $a->printKeys, <
971             SA0 5 1
972             Rr1 3 2->1
973             Lz3 1 3->4
974             Rd2 2 4->2
975             Rz3 1 5->4
976             END
977             #save $a;
978              
979             $b->balance;
980             is_deeply $a->printKeys, <
981             SA0 4 1
982             Lr2 2 2->4
983             Rz3 1 3->2
984             Rd1 3 4->1
985             Rz2 1 5->4
986             END
987             #save $a;
988             }
989              
990              
991             =head2 empty($tree)
992              
993             Return the tree if it is empty
994              
995             Parameter Description
996             1 $tree Tree
997              
998             B
999              
1000              
1001             if (1)
1002             {lll "Balance";
1003             my $t = Tree::Bulk::new->setKeysPerNode(1);
1004              
1005             ok $t->empty; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1006              
1007             ok $t->singleton;
1008             }
1009              
1010              
1011             =head2 singleton($tree)
1012              
1013             Return the tree if it contains only the root node and nothing else
1014              
1015             Parameter Description
1016             1 $tree Tree
1017              
1018             B
1019              
1020              
1021             if (1)
1022             {lll "Balance";
1023             my $t = Tree::Bulk::new->setKeysPerNode(1);
1024             ok $t->empty;
1025              
1026             ok $t->singleton; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1027              
1028             }
1029              
1030              
1031             =head2 isLeftChild($tree)
1032              
1033             Return the tree if it is the left child
1034              
1035             Parameter Description
1036             1 $tree Tree
1037              
1038             B
1039              
1040              
1041             if (1)
1042             {lll "Attributes";
1043             my $t = Tree::Bulk::new->setKeysPerNode(1);
1044             my $b = $t->insert(2,4);
1045             my $a = $t->insert(1,2);
1046             my $c = $t->insert(3,6);
1047              
1048             ok $a->isLeftChild; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1049              
1050             ok $c->isRightChild;
1051             ok !$a->isRightChild;
1052              
1053             ok !$c->isLeftChild; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1054              
1055             ok $b->isRoot;
1056             ok !$a->isRoot;
1057             ok !$c->isRoot;
1058             ok $a->leaf;
1059             ok $c->leaf;
1060             ok $b->duplex;
1061             ok $c->root == $b;
1062             ok $c->root != $a;
1063             }
1064              
1065              
1066             =head2 isRightChild($tree)
1067              
1068             Return the tree if it is the right child
1069              
1070             Parameter Description
1071             1 $tree Tree
1072              
1073             B
1074              
1075              
1076             if (1)
1077             {lll "Attributes";
1078             my $t = Tree::Bulk::new->setKeysPerNode(1);
1079             my $b = $t->insert(2,4);
1080             my $a = $t->insert(1,2);
1081             my $c = $t->insert(3,6);
1082             ok $a->isLeftChild;
1083              
1084             ok $c->isRightChild; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1085              
1086              
1087             ok !$a->isRightChild; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1088              
1089             ok !$c->isLeftChild;
1090             ok $b->isRoot;
1091             ok !$a->isRoot;
1092             ok !$c->isRoot;
1093             ok $a->leaf;
1094             ok $c->leaf;
1095             ok $b->duplex;
1096             ok $c->root == $b;
1097             ok $c->root != $a;
1098             }
1099              
1100              
1101             =head2 name($tree)
1102              
1103             Name of a tree
1104              
1105             Parameter Description
1106             1 $tree Tree
1107              
1108             B
1109              
1110              
1111             if (1)
1112             {lll "Split and Refill";
1113             my $N = 22;
1114             my $t = Tree::Bulk::new;
1115             for my $k(1..$N)
1116             {$t->insert($k, 2 * $k);
1117             }
1118              
1119              
1120             is_deeply $t->name, "1 2 3 4"; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1121              
1122              
1123             is_deeply $t->printKeys, <
1124             SA0 4 1 2 3 4
1125             Lz2 1 5 6 7 8->9 10 11 12
1126             Rd1 3 9 10 11 12->1 2 3 4
1127             Lz3 1 13 14 15 16->17 18 19 20
1128             Rd2 2 17 18 19 20->9 10 11 12
1129             Rz3 1 21 22->17 18 19 20
1130             END
1131             #save $t;
1132              
1133             for my $n($t->inorder)
1134             {$n->setKeysPerNode(2);
1135             }
1136             is_deeply $t->printKeys, <
1137             SA0 5 1 2
1138             Lz3 1 3 4->5 6
1139             Ld2 2 5 6->9 10
1140             Rz3 1 7 8->5 6
1141             Rd1 4 9 10->1 2
1142             Lz4 1 11 12->13 14
1143             Ld3 2 13 14->17 18
1144             Rz4 1 15 16->13 14
1145             Rd2 3 17 18->9 10
1146             Rr3 2 19 20->17 18
1147             Rz4 1 21 22->19 20
1148             END
1149             #save $t;
1150              
1151             for my $n($t->inorder)
1152             {$n->setKeysPerNode(1);
1153             }
1154             is_deeply $t->printKeys, <
1155             SA0 6 1
1156             Lz4 1 2->3
1157             Ld3 2 3->5
1158             Rz4 1 4->3
1159             Ld2 3 5->9
1160             Lz4 1 6->7
1161             Rd3 2 7->5
1162             Rz4 1 8->7
1163             Rd1 5 9->1
1164             Lz5 1 10->11
1165             Ld4 2 11->13
1166             Rz5 1 12->11
1167             Ld3 3 13->17
1168             Lz5 1 14->15
1169             Rd4 2 15->13
1170             Rz5 1 16->15
1171             Rd2 4 17->9
1172             Lz4 1 18->19
1173             Rd3 3 19->17
1174             Lz5 1 20->21
1175             Rd4 2 21->19
1176             Rz5 1 22->21
1177             END
1178             #save $t;
1179              
1180             $_->setKeysPerNode(2) for $t->inorder;
1181             is_deeply $t->printKeys, <
1182             SA0 5 1 2
1183             Lz3 1 3 4->5 6
1184             Ld2 2 5 6->9 10
1185             Rz3 1 7 8->5 6
1186             Rd1 4 9 10->1 2
1187             Lz4 1 11 12->13 14
1188             Ld3 2 13 14->17 18
1189             Rz4 1 15 16->13 14
1190             Rd2 3 17 18->9 10
1191             Lz4 1 19 20->21 22
1192             Rl3 2 21 22->17 18
1193             END
1194             #save $t;
1195              
1196             $_->setKeysPerNode(4) for $t->inorder;
1197             is_deeply $t->printKeys, <
1198             SA0 4 1 2 3 4
1199             Lz2 1 5 6 7 8->9 10 11 12
1200             Rd1 3 9 10 11 12->1 2 3 4
1201             Lz3 1 13 14 15 16->17 18 19 20
1202             Rd2 2 17 18 19 20->9 10 11 12
1203             Rz3 1 21 22->17 18 19 20
1204             END
1205             #save $t;
1206             }
1207              
1208              
1209             =head2 names($tree)
1210              
1211             Names of all nodes in a tree in order
1212              
1213             Parameter Description
1214             1 $tree Tree
1215              
1216             B
1217              
1218              
1219             if (1)
1220             {my sub randomLoad($$$) # Randomly load different size nodes
1221             {my ($N, $keys, $height) = @_; # Number of elements, number of keys per node, expected height
1222              
1223             lll "Random load $keys";
1224              
1225             srand(1); # Same randomization
1226             my $t = Tree::Bulk::new->setKeysPerNode($keys);
1227             for my $r(randomizeArray 1..$N)
1228             {$debug = $r == 74;
1229             $t->insert($r, 2 * $r);
1230             $t->check;
1231             }
1232              
1233             is_deeply $t->actualHeight, $height; # Check height
1234             confess unless $t->actualHeight == $height;
1235              
1236             is_deeply join(' ', 1..$N), $t->names; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1237              
1238              
1239             my %t = map {$_=>2*$_} 1..$N;
1240             for my $r(randomizeArray 1..$N) # Delete in random order
1241             {$t->delete ($r);
1242             delete $t{$r};
1243             checkAgainstHash $t, %t;
1244             check($t);
1245             }
1246              
1247             ok $t->empty;
1248             is_deeply $t->actualHeight, 1;
1249             }
1250              
1251             randomLoad(222, 1, 11);
1252             randomLoad(222, 8, 8);
1253             randomLoad(222, 4, 9);
1254             }
1255              
1256              
1257             =head2 balance($t)
1258              
1259             Balance a node
1260              
1261             Parameter Description
1262             1 $t Tree
1263              
1264             B
1265              
1266              
1267             if (1)
1268             {lll "Balance";
1269             my $t = Tree::Bulk::new->setKeysPerNode(1);
1270              
1271             my $a = node(1,2) ->setKeysPerNode(1);
1272             my $b = node(2,4) ->setKeysPerNode(1);
1273             my $c = node(6,12)->setKeysPerNode(1);
1274             my $d = node(5,10)->setKeysPerNode(1);
1275             my $e = node(4,8) ->setKeysPerNode(1);
1276             my $f = node(3,6) ->setKeysPerNode(1);
1277             $a->right = $b; $b->up = $a;
1278             $b->right = $c; $c->up = $b;
1279             $c->left = $d; $d->up = $c;
1280             $d->left = $e; $e->up = $d;
1281             $e->left = $f; $f->up = $e;
1282             $f->setHeights(1);
1283             is_deeply $a->printKeys, <
1284             SA0 4 1
1285             Lr2 2 2->4
1286             Rz3 1 3->2
1287             Rd1 3 4->1
1288             Lz3 1 5->6
1289             Rl2 2 6->4
1290             END
1291             #save $a;
1292              
1293              
1294             $b->balance; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1295              
1296             is_deeply $a->printKeys, <
1297             SA0 4 1
1298             Lr2 2 2->4
1299             Rz3 1 3->2
1300             Rd1 3 4->1
1301             Lz3 1 5->6
1302             Rl2 2 6->4
1303             END
1304             #save $a;
1305             }
1306              
1307              
1308             =head2 insert($tree, $key, $data)
1309              
1310             Insert a key and some data into a tree
1311              
1312             Parameter Description
1313             1 $tree Tree
1314             2 $key Key
1315             3 $data Data
1316              
1317             B
1318              
1319              
1320             if (1)
1321             {lll "Insert";
1322             my $N = 23;
1323             my $t = Tree::Bulk::new->setKeysPerNode(1);
1324             for(1..$N)
1325              
1326             {$t->insert($_, 2 * $_); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1327              
1328             }
1329              
1330             is_deeply $t->printKeys, <
1331             SA0 8 1
1332             Lz4 1 2->3
1333             Ld3 2 3->5
1334             Rz4 1 4->3
1335             Ld2 3 5->9
1336             Lz4 1 6->7
1337             Rd3 2 7->5
1338             Rz4 1 8->7
1339             Rd1 7 9->1
1340             Lz4 1 10->11
1341             Ld3 2 11->13
1342             Rz4 1 12->11
1343             Rd2 6 13->9
1344             Lz5 1 14->15
1345             Ld4 2 15->17
1346             Rz5 1 16->15
1347             Rd3 5 17->13
1348             Lz5 1 18->19
1349             Rd4 4 19->17
1350             Lz6 1 20->21
1351             Rd5 3 21->19
1352             Rr6 2 22->21
1353             Rz7 1 23->22
1354             END
1355             #save $t;
1356             ok $t->height == 8;
1357             }
1358              
1359              
1360             =head2 find($tree, $key)
1361              
1362             Find a key in a tree and returns its data
1363              
1364             Parameter Description
1365             1 $tree Tree
1366             2 $key Key
1367              
1368             B
1369              
1370              
1371             if (1)
1372             {my $t = Tree::Bulk::new;
1373             $t->insert($_, $_*$_) for 1..20;
1374              
1375             ok !find($t, 0); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1376              
1377              
1378             ok !find($t, 21); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1379              
1380              
1381             ok find($t, $_) == $_ * $_ for qw(1 5 10 11 15 20); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1382              
1383             }
1384              
1385              
1386             =head2 first($n)
1387              
1388             First node in a tree
1389              
1390             Parameter Description
1391             1 $n Tree
1392              
1393             B
1394              
1395              
1396             if (1)
1397             {my $N = 220;
1398             my $t = Tree::Bulk::new;
1399              
1400             for(reverse 1..$N)
1401             {$t->insert($_, 2*$_);
1402             }
1403              
1404             is_deeply $t->actualHeight, 10;
1405              
1406             if (1)
1407             {my @n;
1408              
1409             for (my $n = $t->first; $n; $n = $n->next) # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1410              
1411             {push @n, $n->keys->@*
1412             }
1413             is_deeply \@n, [1..$N];
1414             }
1415              
1416             if (1)
1417             {my @p;
1418             for my $p(reverse $t->inorder)
1419             {push @p, reverse $p->keys->@*;
1420             }
1421             is_deeply \@p, [reverse 1..$N];
1422             }
1423              
1424             my @p;
1425             for(my $p = $t->last; $p; $p = $p->prev)
1426             {push @p, reverse $p->keys->@*
1427             }
1428             is_deeply \@p, [reverse 1..$N];
1429              
1430             my %t = map {$_=>2*$_} 1..$N;
1431             for my $i(0..3)
1432             {for my $j(map {4 * $_-$i} 1..$N/4)
1433             {$t->delete ($j);
1434             delete $t{$j};
1435             checkAgainstHash $t, %t;
1436             }
1437             }
1438              
1439             ok $t->empty;
1440             is_deeply $t->actualHeight, 1;
1441             }
1442              
1443              
1444             =head2 last($n)
1445              
1446             Last node in a tree
1447              
1448             Parameter Description
1449             1 $n Tree
1450              
1451             B
1452              
1453              
1454             if (1)
1455             {my $N = 220;
1456             my $t = Tree::Bulk::new;
1457              
1458             for(reverse 1..$N)
1459             {$t->insert($_, 2*$_);
1460             }
1461              
1462             is_deeply $t->actualHeight, 10;
1463              
1464             if (1)
1465             {my @n;
1466             for (my $n = $t->first; $n; $n = $n->next)
1467             {push @n, $n->keys->@*
1468             }
1469             is_deeply \@n, [1..$N];
1470             }
1471              
1472             if (1)
1473             {my @p;
1474             for my $p(reverse $t->inorder)
1475             {push @p, reverse $p->keys->@*;
1476             }
1477             is_deeply \@p, [reverse 1..$N];
1478             }
1479              
1480             my @p;
1481              
1482             for(my $p = $t->last; $p; $p = $p->prev) # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1483              
1484             {push @p, reverse $p->keys->@*
1485             }
1486             is_deeply \@p, [reverse 1..$N];
1487              
1488             my %t = map {$_=>2*$_} 1..$N;
1489             for my $i(0..3)
1490             {for my $j(map {4 * $_-$i} 1..$N/4)
1491             {$t->delete ($j);
1492             delete $t{$j};
1493             checkAgainstHash $t, %t;
1494             }
1495             }
1496              
1497             ok $t->empty;
1498             is_deeply $t->actualHeight, 1;
1499             }
1500              
1501              
1502             =head2 next($tree)
1503              
1504             Next node in order
1505              
1506             Parameter Description
1507             1 $tree Tree
1508              
1509             B
1510              
1511              
1512             if (1)
1513             {my $N = 220;
1514             my $t = Tree::Bulk::new;
1515              
1516             for(reverse 1..$N)
1517             {$t->insert($_, 2*$_);
1518             }
1519              
1520             is_deeply $t->actualHeight, 10;
1521              
1522             if (1)
1523             {my @n;
1524              
1525             for (my $n = $t->first; $n; $n = $n->next) # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1526              
1527             {push @n, $n->keys->@*
1528             }
1529             is_deeply \@n, [1..$N];
1530             }
1531              
1532             if (1)
1533             {my @p;
1534             for my $p(reverse $t->inorder)
1535             {push @p, reverse $p->keys->@*;
1536             }
1537             is_deeply \@p, [reverse 1..$N];
1538             }
1539              
1540             my @p;
1541             for(my $p = $t->last; $p; $p = $p->prev)
1542             {push @p, reverse $p->keys->@*
1543             }
1544             is_deeply \@p, [reverse 1..$N];
1545              
1546             my %t = map {$_=>2*$_} 1..$N;
1547             for my $i(0..3)
1548             {for my $j(map {4 * $_-$i} 1..$N/4)
1549             {$t->delete ($j);
1550             delete $t{$j};
1551             checkAgainstHash $t, %t;
1552             }
1553             }
1554              
1555             ok $t->empty;
1556             is_deeply $t->actualHeight, 1;
1557             }
1558              
1559              
1560             =head2 prev($tree)
1561              
1562             Previous node in order
1563              
1564             Parameter Description
1565             1 $tree Tree
1566              
1567             B
1568              
1569              
1570             if (1)
1571             {my $N = 220;
1572             my $t = Tree::Bulk::new;
1573              
1574             for(reverse 1..$N)
1575             {$t->insert($_, 2*$_);
1576             }
1577              
1578             is_deeply $t->actualHeight, 10;
1579              
1580             if (1)
1581             {my @n;
1582             for (my $n = $t->first; $n; $n = $n->next)
1583             {push @n, $n->keys->@*
1584             }
1585             is_deeply \@n, [1..$N];
1586             }
1587              
1588             if (1)
1589             {my @p;
1590             for my $p(reverse $t->inorder)
1591             {push @p, reverse $p->keys->@*;
1592             }
1593             is_deeply \@p, [reverse 1..$N];
1594             }
1595              
1596             my @p;
1597              
1598             for(my $p = $t->last; $p; $p = $p->prev) # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1599              
1600             {push @p, reverse $p->keys->@*
1601             }
1602             is_deeply \@p, [reverse 1..$N];
1603              
1604             my %t = map {$_=>2*$_} 1..$N;
1605             for my $i(0..3)
1606             {for my $j(map {4 * $_-$i} 1..$N/4)
1607             {$t->delete ($j);
1608             delete $t{$j};
1609             checkAgainstHash $t, %t;
1610             }
1611             }
1612              
1613             ok $t->empty;
1614             is_deeply $t->actualHeight, 1;
1615             }
1616              
1617              
1618             =head2 inorder($tree)
1619              
1620             Return a list of all the nodes in a tree in order
1621              
1622             Parameter Description
1623             1 $tree Tree
1624              
1625             B
1626              
1627              
1628             if (1)
1629             {my $N = 220;
1630             my $t = Tree::Bulk::new;
1631              
1632             for(reverse 1..$N)
1633             {$t->insert($_, 2*$_);
1634             }
1635              
1636             is_deeply $t->actualHeight, 10;
1637              
1638             if (1)
1639             {my @n;
1640             for (my $n = $t->first; $n; $n = $n->next)
1641             {push @n, $n->keys->@*
1642             }
1643             is_deeply \@n, [1..$N];
1644             }
1645              
1646             if (1)
1647             {my @p;
1648              
1649             for my $p(reverse $t->inorder) # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1650              
1651             {push @p, reverse $p->keys->@*;
1652             }
1653             is_deeply \@p, [reverse 1..$N];
1654             }
1655              
1656             my @p;
1657             for(my $p = $t->last; $p; $p = $p->prev)
1658             {push @p, reverse $p->keys->@*
1659             }
1660             is_deeply \@p, [reverse 1..$N];
1661              
1662             my %t = map {$_=>2*$_} 1..$N;
1663             for my $i(0..3)
1664             {for my $j(map {4 * $_-$i} 1..$N/4)
1665             {$t->delete ($j);
1666             delete $t{$j};
1667             checkAgainstHash $t, %t;
1668             }
1669             }
1670              
1671             ok $t->empty;
1672             is_deeply $t->actualHeight, 1;
1673             }
1674              
1675              
1676             =head2 delete($tree, $key)
1677              
1678             Delete a key in a tree
1679              
1680             Parameter Description
1681             1 $tree Tree
1682             2 $key Key
1683              
1684             B
1685              
1686              
1687             if (1)
1688             {lll "Delete";
1689             my $N = 28;
1690             my $t = Tree::Bulk::new->setKeysPerNode(1);
1691             for(1..$N)
1692             {$t->insert($_, 2 * $_);
1693             }
1694              
1695             is_deeply $t->printKeys, <
1696             SA0 8 1
1697             Lz4 1 2->3
1698             Ld3 2 3->5
1699             Rz4 1 4->3
1700             Ld2 3 5->9
1701             Lz4 1 6->7
1702             Rd3 2 7->5
1703             Rz4 1 8->7
1704             Rd1 7 9->1
1705             Lz5 1 10->11
1706             Ld4 2 11->13
1707             Rz5 1 12->11
1708             Ld3 3 13->17
1709             Lz5 1 14->15
1710             Rd4 2 15->13
1711             Rz5 1 16->15
1712             Rd2 6 17->9
1713             Lz5 1 18->19
1714             Ld4 2 19->21
1715             Rz5 1 20->19
1716             Rd3 5 21->17
1717             Lz5 1 22->23
1718             Rd4 4 23->21
1719             Lz6 1 24->25
1720             Rd5 3 25->23
1721             Lz7 1 26->27
1722             Rd6 2 27->25
1723             Rz7 1 28->27
1724             END
1725             #save $t;
1726              
1727             for my $k(reverse 1..$N)
1728              
1729             {$t->delete($k); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1730              
1731             is_deeply $t->printKeys, <
1732             SA0 5 1
1733             Lz4 1 2->3
1734             Ld3 2 3->5
1735             Rz4 1 4->3
1736             Ld2 3 5->9
1737             Lz4 1 6->7
1738             Rd3 2 7->5
1739             Rz4 1 8->7
1740             Rd1 4 9->1
1741             Lz4 1 10->11
1742             Ld3 2 11->13
1743             Rz4 1 12->11
1744             Rd2 3 13->9
1745             Lz4 1 14->15
1746             Rd3 2 15->13
1747             Rz4 1 16->15
1748             END
1749             #save $t if $k == 17;
1750              
1751             is_deeply $t->printKeys, <
1752             SA0 4 1
1753             Lz3 1 2->3
1754             Ld2 2 3->5
1755             Rz3 1 4->3
1756             Rd1 3 5->1
1757             Lz3 1 6->7
1758             Rd2 2 7->5
1759             Rz3 1 8->7
1760             END
1761             #save $t if $k == 9;
1762              
1763             is_deeply $t->printKeys, <
1764             SA0 4 1
1765             Lz2 1 2->3
1766             Rd1 3 3->1
1767             Lz3 1 4->5
1768             Rl2 2 5->3
1769             END
1770             #save $t if $k == 6;
1771              
1772             is_deeply $t->printKeys, <
1773             SA0 3 1
1774             Rr1 2 2->1
1775             Rz2 1 3->2
1776             END
1777             #save $t if $k == 4;
1778              
1779             is_deeply $t->printKeys, <
1780             SA0 2 1
1781             Rz1 1 2->1
1782             END
1783             #save $t if $k == 3;
1784              
1785             is_deeply $t->printKeys, <
1786             Sz0 1
1787             END
1788             #save $t if $k == 1;
1789             }
1790             }
1791              
1792              
1793             =head2 printKeys($t)
1794              
1795             Print the keys in a tree
1796              
1797             Parameter Description
1798             1 $t Tree
1799              
1800             B
1801              
1802              
1803             if (1)
1804             {lll "Insert";
1805             my $N = 23;
1806             my $t = Tree::Bulk::new->setKeysPerNode(1);
1807             for(1..$N)
1808             {$t->insert($_, 2 * $_);
1809             }
1810              
1811              
1812             is_deeply $t->printKeys, <
1813              
1814             SA0 8 1
1815             Lz4 1 2->3
1816             Ld3 2 3->5
1817             Rz4 1 4->3
1818             Ld2 3 5->9
1819             Lz4 1 6->7
1820             Rd3 2 7->5
1821             Rz4 1 8->7
1822             Rd1 7 9->1
1823             Lz4 1 10->11
1824             Ld3 2 11->13
1825             Rz4 1 12->11
1826             Rd2 6 13->9
1827             Lz5 1 14->15
1828             Ld4 2 15->17
1829             Rz5 1 16->15
1830             Rd3 5 17->13
1831             Lz5 1 18->19
1832             Rd4 4 19->17
1833             Lz6 1 20->21
1834             Rd5 3 21->19
1835             Rr6 2 22->21
1836             Rz7 1 23->22
1837             END
1838             #save $t;
1839             ok $t->height == 8;
1840             }
1841              
1842              
1843             =head2 setKeysPerNode($tree, $N)
1844              
1845             Set the number of keys for the current node
1846              
1847             Parameter Description
1848             1 $tree Tree
1849             2 $N Keys per node to be set
1850              
1851             B
1852              
1853              
1854             if (1)
1855             {lll "Split and Refill";
1856             my $N = 22;
1857             my $t = Tree::Bulk::new;
1858             for my $k(1..$N)
1859             {$t->insert($k, 2 * $k);
1860             }
1861              
1862             is_deeply $t->name, "1 2 3 4";
1863              
1864             is_deeply $t->printKeys, <
1865             SA0 4 1 2 3 4
1866             Lz2 1 5 6 7 8->9 10 11 12
1867             Rd1 3 9 10 11 12->1 2 3 4
1868             Lz3 1 13 14 15 16->17 18 19 20
1869             Rd2 2 17 18 19 20->9 10 11 12
1870             Rz3 1 21 22->17 18 19 20
1871             END
1872             #save $t;
1873              
1874             for my $n($t->inorder)
1875              
1876             {$n->setKeysPerNode(2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1877              
1878             }
1879             is_deeply $t->printKeys, <
1880             SA0 5 1 2
1881             Lz3 1 3 4->5 6
1882             Ld2 2 5 6->9 10
1883             Rz3 1 7 8->5 6
1884             Rd1 4 9 10->1 2
1885             Lz4 1 11 12->13 14
1886             Ld3 2 13 14->17 18
1887             Rz4 1 15 16->13 14
1888             Rd2 3 17 18->9 10
1889             Rr3 2 19 20->17 18
1890             Rz4 1 21 22->19 20
1891             END
1892             #save $t;
1893              
1894             for my $n($t->inorder)
1895              
1896             {$n->setKeysPerNode(1); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1897              
1898             }
1899             is_deeply $t->printKeys, <
1900             SA0 6 1
1901             Lz4 1 2->3
1902             Ld3 2 3->5
1903             Rz4 1 4->3
1904             Ld2 3 5->9
1905             Lz4 1 6->7
1906             Rd3 2 7->5
1907             Rz4 1 8->7
1908             Rd1 5 9->1
1909             Lz5 1 10->11
1910             Ld4 2 11->13
1911             Rz5 1 12->11
1912             Ld3 3 13->17
1913             Lz5 1 14->15
1914             Rd4 2 15->13
1915             Rz5 1 16->15
1916             Rd2 4 17->9
1917             Lz4 1 18->19
1918             Rd3 3 19->17
1919             Lz5 1 20->21
1920             Rd4 2 21->19
1921             Rz5 1 22->21
1922             END
1923             #save $t;
1924              
1925              
1926             $_->setKeysPerNode(2) for $t->inorder; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1927              
1928             is_deeply $t->printKeys, <
1929             SA0 5 1 2
1930             Lz3 1 3 4->5 6
1931             Ld2 2 5 6->9 10
1932             Rz3 1 7 8->5 6
1933             Rd1 4 9 10->1 2
1934             Lz4 1 11 12->13 14
1935             Ld3 2 13 14->17 18
1936             Rz4 1 15 16->13 14
1937             Rd2 3 17 18->9 10
1938             Lz4 1 19 20->21 22
1939             Rl3 2 21 22->17 18
1940             END
1941             #save $t;
1942              
1943              
1944             $_->setKeysPerNode(4) for $t->inorder; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1945              
1946             is_deeply $t->printKeys, <
1947             SA0 4 1 2 3 4
1948             Lz2 1 5 6 7 8->9 10 11 12
1949             Rd1 3 9 10 11 12->1 2 3 4
1950             Lz3 1 13 14 15 16->17 18 19 20
1951             Rd2 2 17 18 19 20->9 10 11 12
1952             Rz3 1 21 22->17 18 19 20
1953             END
1954             #save $t;
1955             }
1956              
1957              
1958             =head2 printKeysAndData($t)
1959              
1960             Print the mapping from keys to data in a tree
1961              
1962             Parameter Description
1963             1 $t Tree
1964              
1965             B
1966              
1967              
1968             if (1)
1969             {my $N = 22;
1970             my $t = Tree::Bulk::new;
1971             ok $t->empty;
1972             ok $t->leaf;
1973              
1974             for(1..$N)
1975             {$t->insert($_, 2 * $_);
1976             }
1977              
1978             ok $t->right->duplex;
1979             is_deeply actualHeight($t), 4;
1980              
1981             is_deeply $t->printKeys, <
1982             SA0 4 1 2 3 4
1983             Lz2 1 5 6 7 8->9 10 11 12
1984             Rd1 3 9 10 11 12->1 2 3 4
1985             Lz3 1 13 14 15 16->17 18 19 20
1986             Rd2 2 17 18 19 20->9 10 11 12
1987             Rz3 1 21 22->17 18 19 20
1988             END
1989             #save $t;
1990              
1991              
1992             is_deeply $t->printKeysAndData, <
1993              
1994             1 2
1995             2 4
1996             3 6
1997             4 8
1998             5 10
1999             6 12
2000             7 14
2001             8 16
2002             9 18
2003             10 20
2004             11 22
2005             12 24
2006             13 26
2007             14 28
2008             15 30
2009             16 32
2010             17 34
2011             18 36
2012             19 38
2013             20 40
2014             21 42
2015             22 44
2016             END
2017              
2018             my %t = map {$_=>2*$_} 1..$N;
2019              
2020             for(map {2 * $_} 1..$N/2)
2021             {$t->delete($_);
2022             delete $t{$_};
2023             checkAgainstHash $t, %t;
2024             }
2025              
2026             is_deeply $t->printKeys, <
2027             SA0 3 1 3 5 7
2028             Rr1 2 9 11 13 15->1 3 5 7
2029             Rz2 1 17 19 21->9 11 13 15
2030             END
2031             #save($t);
2032              
2033              
2034             is_deeply $t->printKeysAndData, <
2035              
2036             1 2
2037             3 6
2038             5 10
2039             7 14
2040             9 18
2041             11 22
2042             13 26
2043             15 30
2044             17 34
2045             19 38
2046             21 42
2047             END
2048              
2049             for(map {2 * $_-1} 1..$N/2)
2050             {$t->delete($_);
2051             delete $t{$_};
2052             checkAgainstHash $t, %t;
2053             }
2054              
2055             is_deeply $t->printKeys, <
2056             Sz0 1
2057             END
2058             #save($t);
2059             }
2060              
2061              
2062              
2063             =head2 Tree::Bulk Definition
2064              
2065              
2066             Bulk tree node
2067              
2068              
2069              
2070              
2071             =head3 Output fields
2072              
2073              
2074             =head4 data
2075              
2076             Data corresponding to each key
2077              
2078             =head4 height
2079              
2080             Height of node
2081              
2082             =head4 keys
2083              
2084             Array of data items for this node
2085              
2086             =head4 keysPerNode
2087              
2088             Maximum number of keys per node
2089              
2090             =head4 left
2091              
2092             Left node
2093              
2094             =head4 right
2095              
2096             Right node
2097              
2098             =head4 up
2099              
2100             Parent node
2101              
2102              
2103              
2104             =head1 Attributes
2105              
2106              
2107             The following is a list of all the attributes in this package. A method coded
2108             with the same name in your package will over ride the method of the same name
2109             in this package and thus provide your value for the attribute in place of the
2110             default value supplied for this attribute by this package.
2111              
2112             =head2 Replaceable Attribute List
2113              
2114              
2115             new
2116              
2117              
2118             =head2 new
2119              
2120             Create a new tree
2121              
2122              
2123              
2124              
2125             =head1 Private Methods
2126              
2127             =head2 node($key, $data, $up, $side)
2128              
2129             Create a new bulk tree node
2130              
2131             Parameter Description
2132             1 $key Key
2133             2 $data $data
2134             3 $up Parent node
2135             4 $side Side of parent node
2136              
2137             =head2 setHeights($tree)
2138              
2139             Set heights along path to root
2140              
2141             Parameter Description
2142             1 $tree Tree
2143              
2144             B
2145              
2146              
2147             if (1)
2148             {lll "Balance";
2149             my $t = Tree::Bulk::new->setKeysPerNode(1);
2150              
2151             my $a = node(1,2) ->setKeysPerNode(1);
2152             my $b = node(2,4) ->setKeysPerNode(1);
2153             my $c = node(6,12)->setKeysPerNode(1);
2154             my $d = node(5,10)->setKeysPerNode(1);
2155             my $e = node(4,8) ->setKeysPerNode(1);
2156             my $f = node(3,6) ->setKeysPerNode(1);
2157             $a->right = $b; $b->up = $a;
2158             $b->right = $c; $c->up = $b;
2159             $c->left = $d; $d->up = $c;
2160             $d->left = $e; $e->up = $d;
2161             $e->left = $f; $f->up = $e;
2162              
2163             $f->setHeights(1); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2164              
2165             is_deeply $a->printKeys, <
2166             SA0 4 1
2167             Lr2 2 2->4
2168             Rz3 1 3->2
2169             Rd1 3 4->1
2170             Lz3 1 5->6
2171             Rl2 2 6->4
2172             END
2173             #save $a;
2174              
2175             $b->balance;
2176             is_deeply $a->printKeys, <
2177             SA0 4 1
2178             Lr2 2 2->4
2179             Rz3 1 3->2
2180             Rd1 3 4->1
2181             Lz3 1 5->6
2182             Rl2 2 6->4
2183             END
2184             #save $a;
2185             }
2186              
2187              
2188             =head2 actualHeight($tree)
2189              
2190             Get the height of a node
2191              
2192             Parameter Description
2193             1 $tree Tree
2194              
2195             B
2196              
2197              
2198             if (1)
2199             {my $N = 22;
2200             my $t = Tree::Bulk::new;
2201             ok $t->empty;
2202             ok $t->leaf;
2203              
2204             for(1..$N)
2205             {$t->insert($_, 2 * $_);
2206             }
2207              
2208             ok $t->right->duplex;
2209              
2210             is_deeply actualHeight($t), 4; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2211              
2212              
2213             is_deeply $t->printKeys, <
2214             SA0 4 1 2 3 4
2215             Lz2 1 5 6 7 8->9 10 11 12
2216             Rd1 3 9 10 11 12->1 2 3 4
2217             Lz3 1 13 14 15 16->17 18 19 20
2218             Rd2 2 17 18 19 20->9 10 11 12
2219             Rz3 1 21 22->17 18 19 20
2220             END
2221             #save $t;
2222              
2223             is_deeply $t->printKeysAndData, <
2224             1 2
2225             2 4
2226             3 6
2227             4 8
2228             5 10
2229             6 12
2230             7 14
2231             8 16
2232             9 18
2233             10 20
2234             11 22
2235             12 24
2236             13 26
2237             14 28
2238             15 30
2239             16 32
2240             17 34
2241             18 36
2242             19 38
2243             20 40
2244             21 42
2245             22 44
2246             END
2247              
2248             my %t = map {$_=>2*$_} 1..$N;
2249              
2250             for(map {2 * $_} 1..$N/2)
2251             {$t->delete($_);
2252             delete $t{$_};
2253             checkAgainstHash $t, %t;
2254             }
2255              
2256             is_deeply $t->printKeys, <
2257             SA0 3 1 3 5 7
2258             Rr1 2 9 11 13 15->1 3 5 7
2259             Rz2 1 17 19 21->9 11 13 15
2260             END
2261             #save($t);
2262              
2263             is_deeply $t->printKeysAndData, <
2264             1 2
2265             3 6
2266             5 10
2267             7 14
2268             9 18
2269             11 22
2270             13 26
2271             15 30
2272             17 34
2273             19 38
2274             21 42
2275             END
2276              
2277             for(map {2 * $_-1} 1..$N/2)
2278             {$t->delete($_);
2279             delete $t{$_};
2280             checkAgainstHash $t, %t;
2281             }
2282              
2283             is_deeply $t->printKeys, <
2284             Sz0 1
2285             END
2286             #save($t);
2287             }
2288              
2289              
2290             =head2 maximum($a, $b)
2291              
2292             Maximum of two numbers
2293              
2294             Parameter Description
2295             1 $a First
2296             2 $b Second
2297              
2298             B
2299              
2300              
2301             if (1)
2302              
2303             {is_deeply maximum(1,2), 2; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2304              
2305              
2306             is_deeply maximum(2,1), 2; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2307              
2308             }
2309              
2310              
2311             =head2 setHeight($tree)
2312              
2313             Set height of a tree from its left and right trees
2314              
2315             Parameter Description
2316             1 $tree Tree
2317              
2318             =head2 rotateLeft($n)
2319              
2320             Rotate a node left
2321              
2322             Parameter Description
2323             1 $n Node
2324              
2325             B
2326              
2327              
2328             if (1)
2329             {lll "Rotate";
2330             my $a = node(1,2)->setKeysPerNode(1);
2331             my $b = node(2,4)->setKeysPerNode(1);
2332             my $c = node(3,6)->setKeysPerNode(1);
2333             my $d = node(4,8)->setKeysPerNode(1);
2334             $a->right = $b; $b->up = $a;
2335             $b->right = $c; $c->up = $b;
2336             $c->right = $d; $d->up = $c;
2337             $d->setHeights(1);
2338              
2339             is_deeply $a->printKeys, <
2340             SA0 3 1
2341             Lz2 1 2->3
2342             Rd1 2 3->1
2343             Rz2 1 4->3
2344             END
2345             #save $a;
2346              
2347             $b->rotateLeft; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2348              
2349             is_deeply $a->printKeys, <
2350             SA0 3 1
2351             Lz2 1 2->3
2352             Rd1 2 3->1
2353             Rz2 1 4->3
2354             END
2355             #save $a;
2356              
2357              
2358             $c->rotateLeft; $c->setHeights(2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2359              
2360             is_deeply $a->printKeys, <
2361             SA0 3 1
2362             Lz2 1 2->3
2363             Rd1 2 3->1
2364             Rz2 1 4->3
2365             END
2366             #save $a;
2367              
2368             $d->rotateRight; $d->setHeights(1);
2369             is_deeply $a->printKeys, <
2370             SA0 3 1
2371             Lz2 1 2->3
2372             Rd1 2 3->1
2373             Rz2 1 4->3
2374             END
2375             #save $a;
2376              
2377             $c->rotateRight; $c->setHeights(2);
2378             is_deeply $a->printKeys, <
2379             SA0 3 1
2380             Lz2 1 2->3
2381             Rd1 2 3->1
2382             Rz2 1 4->3
2383             END
2384             #save $a;
2385             }
2386              
2387              
2388             =head2 rotateRight($n)
2389              
2390             Rotate a node right
2391              
2392             Parameter Description
2393             1 $n Node
2394              
2395             B
2396              
2397              
2398             if (1)
2399             {lll "Rotate";
2400             my $a = node(1,2)->setKeysPerNode(1);
2401             my $b = node(2,4)->setKeysPerNode(1);
2402             my $c = node(3,6)->setKeysPerNode(1);
2403             my $d = node(4,8)->setKeysPerNode(1);
2404             $a->right = $b; $b->up = $a;
2405             $b->right = $c; $c->up = $b;
2406             $c->right = $d; $d->up = $c;
2407             $d->setHeights(1);
2408              
2409             is_deeply $a->printKeys, <
2410             SA0 3 1
2411             Lz2 1 2->3
2412             Rd1 2 3->1
2413             Rz2 1 4->3
2414             END
2415             #save $a;
2416             $b->rotateLeft;
2417             is_deeply $a->printKeys, <
2418             SA0 3 1
2419             Lz2 1 2->3
2420             Rd1 2 3->1
2421             Rz2 1 4->3
2422             END
2423             #save $a;
2424              
2425             $c->rotateLeft; $c->setHeights(2);
2426             is_deeply $a->printKeys, <
2427             SA0 3 1
2428             Lz2 1 2->3
2429             Rd1 2 3->1
2430             Rz2 1 4->3
2431             END
2432             #save $a;
2433              
2434              
2435             $d->rotateRight; $d->setHeights(1); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2436              
2437             is_deeply $a->printKeys, <
2438             SA0 3 1
2439             Lz2 1 2->3
2440             Rd1 2 3->1
2441             Rz2 1 4->3
2442             END
2443             #save $a;
2444              
2445              
2446             $c->rotateRight; $c->setHeights(2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
2447              
2448             is_deeply $a->printKeys, <
2449             SA0 3 1
2450             Lz2 1 2->3
2451             Rd1 2 3->1
2452             Rz2 1 4->3
2453             END
2454             #save $a;
2455             }
2456              
2457              
2458             =head2 insertUnchecked($tree, $key, $data)
2459              
2460             Insert a key and some data into a tree
2461              
2462             Parameter Description
2463             1 $tree Tree
2464             2 $key Key
2465             3 $data Data
2466              
2467             =head2 unchain($t)
2468              
2469             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
2470              
2471             Parameter Description
2472             1 $t Tree
2473              
2474             =head2 refillFromRight($target)
2475              
2476             Push a key to the target node from the next node
2477              
2478             Parameter Description
2479             1 $target Target tree
2480              
2481             =head2 refillFromLeft($target)
2482              
2483             Push a key to the target node from the previous node
2484              
2485             Parameter Description
2486             1 $target Target tree
2487              
2488             =head2 refill($tree)
2489              
2490             Refill a node so it has the expected number of keys
2491              
2492             Parameter Description
2493             1 $tree Tree
2494              
2495             =head2 printKeys2($t, $in, $g)
2496              
2497             print the keys for a tree
2498              
2499             Parameter Description
2500             1 $t Tree
2501             2 $in Indentation
2502             3 $g List of keys
2503              
2504             =head2 checkLRU($tree)
2505              
2506             Confirm pointers in tree
2507              
2508             Parameter Description
2509             1 $tree Tree
2510              
2511             =head2 check($tree)
2512              
2513             Confirm that each node in a tree is ordered correctly
2514              
2515             Parameter Description
2516             1 $tree Tree
2517              
2518             =head2 checkAgainstHash($t, %t)
2519              
2520             Check a tree against a hash
2521              
2522             Parameter Description
2523             1 $t Tree
2524             2 %t Expected
2525              
2526              
2527             =head1 Index
2528              
2529              
2530             1 L - Get the height of a node
2531              
2532             2 L - Balance a node
2533              
2534             3 L - Confirm that each node in a tree is ordered correctly
2535              
2536             4 L - Check a tree against a hash
2537              
2538             5 L - Confirm pointers in tree
2539              
2540             6 L - Delete a key in a tree
2541              
2542             7 L - Return the tree if it has left and right children
2543              
2544             8 L - Return the tree if it is empty
2545              
2546             9 L - Find a key in a tree and returns its data
2547              
2548             10 L - First node in a tree
2549              
2550             11 L - Return a list of all the nodes in a tree in order
2551              
2552             12 L - Insert a key and some data into a tree
2553              
2554             13 L - Insert a key and some data into a tree
2555              
2556             14 L - Return the tree if it is the left child
2557              
2558             15 L - Return the tree if it is the right child
2559              
2560             16 L - Return the tree if it is the root
2561              
2562             17 L - Last node in a tree
2563              
2564             18 L - Return the tree if it is a leaf
2565              
2566             19 L - Maximum of two numbers
2567              
2568             20 L - Name of a tree
2569              
2570             21 L - Names of all nodes in a tree in order
2571              
2572             22 L - Next node in order
2573              
2574             23 L - Create a new bulk tree node
2575              
2576             24 L - Previous node in order
2577              
2578             25 L - Print the keys in a tree
2579              
2580             26 L - print the keys for a tree
2581              
2582             27 L - Print the mapping from keys to data in a tree
2583              
2584             28 L - Refill a node so it has the expected number of keys
2585              
2586             29 L - Push a key to the target node from the previous node
2587              
2588             30 L - Push a key to the target node from the next node
2589              
2590             31 L - Return the root node of a tree
2591              
2592             32 L - Rotate a node left
2593              
2594             33 L - Rotate a node right
2595              
2596             34 L - Set height of a tree from its left and right trees
2597              
2598             35 L - Set heights along path to root
2599              
2600             36 L - Set the number of keys for the current node
2601              
2602             37 L - Return the tree if it has either a left child or a right child but not both.
2603              
2604             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.
2605              
2606             39 L - Return the tree if it contains only the root node and nothing else
2607              
2608             40 L - Remove a tree from the middle of a chain.
2609              
2610             =head1 Installation
2611              
2612             This module is written in 100% Pure Perl and, thus, it is easy to read,
2613             comprehend, use, modify and install via B:
2614              
2615             sudo cpan install Tree::Bulk
2616              
2617             =head1 Author
2618              
2619             L
2620              
2621             L
2622              
2623             =head1 Copyright
2624              
2625             Copyright (c) 2016-2021 Philip R Brenan.
2626              
2627             This module is free software. It may be used, redistributed and/or modified
2628             under the same terms as Perl itself.
2629              
2630             =cut
2631              
2632              
2633              
2634             # Tests and documentation
2635              
2636             sub test
2637 1     1 0 7 {my $p = __PACKAGE__;
2638 1         8 binmode($_, ":utf8") for *STDOUT, *STDERR;
2639 1 50       74 return if eval "eof(${p}::DATA)";
2640 1         56 my $s = eval "join('', <${p}::DATA>)";
2641 1 50       29 $@ and die $@;
2642 1     1   7 eval $s;
  1     1   14  
  1         5  
  1         859  
  1         68409  
  1         8  
  1         77  
2643 1 50       580 $@ and die $@;
2644 1         131 1
2645             }
2646              
2647             test unless caller;
2648              
2649             1;
2650             # podDocumentation
2651             __DATA__