File Coverage

blib/lib/Tree/Bulk.pm
Criterion Covered Total %
statement 277 319 86.8
branch 170 262 64.8
condition 39 82 47.5
subroutine 50 56 89.2
pod 33 38 86.8
total 569 757 75.1


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