File Coverage

blib/lib/Tree/Multi.pm
Criterion Covered Total %
statement 430 453 94.9
branch 197 270 72.9
condition 35 48 72.9
subroutine 54 56 96.4
pod 35 36 97.2
total 751 863 87.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -I/home/phil/perl/cpan/DataTableText/lib/ -I.
2             #-------------------------------------------------------------------------------
3             # Multi-way tree in Pure Perl with an even or odd number of keys per node.
4             # Philip R Brenan at appaapps dot com, Appa Apps Ltd Inc., 2021
5             #-------------------------------------------------------------------------------
6             # podDocumentation
7             package Tree::Multi;
8             our $VERSION = "20210614";
9 1     1   796 use warnings FATAL => qw(all);
  1         7  
  1         39  
10 1     1   5 use strict;
  1         2  
  1         34  
11 1     1   6 use Carp qw(confess cluck);
  1         2  
  1         95  
12 1     1   625 use Data::Dump qw(dump pp);
  1         7688  
  1         65  
13 1     1   3942 use Data::Table::Text qw(:all);
  1         143040  
  1         1878  
14 1     1   13 use feature qw(say current_sub);
  1         2  
  1         6346  
15              
16             our $numberOfKeysPerNode = 3; # Number of keys per node which can be localized because it is ours. The number of keys can be even or odd.
17              
18             #D1 Multi-way Tree # Create and use a multi-way tree.
19              
20             sub new() #P Create a new multi-way tree node.
21 248120     248120 1 7047764 {my () = @_; # Key, $data, parent node, index of link from parent node
22 248120         677756 genHash(__PACKAGE__, # Multi tree node
23             up => undef, # Parent node
24             keys => [], # Array of key items for this node
25             data => [], # Data corresponding to each key
26             node => [], # Child nodes
27             );
28             }
29              
30             sub minimumNumberOfKeys() #P Minimum number of keys per node.
31 1131074     1131074 1 3755046 {int(($numberOfKeysPerNode - 1) / 2)
32             }
33              
34             sub maximumNumberOfKeys() #P Maximum number of keys per node.
35 3869255     3869255 1 14637849 {$numberOfKeysPerNode
36             }
37              
38             sub maximumNumberOfNodes() #P Maximum number of children per parent.
39 122911     122911 1 318490 {$numberOfKeysPerNode + 1
40             }
41              
42             sub full($) #P Confirm that a node is full.
43 0     0 1 0 {my ($tree) = @_; # Tree
44 0 0       0 @_ == 1 or confess;
45 0         0 my $n = $tree->keys->@*;
46 0 0       0 $n <= maximumNumberOfKeys or confess "Keys";
47 0         0 $n == maximumNumberOfKeys
48             }
49              
50             sub halfFull($) #P Confirm that a node is half full.
51 1131074     1131074 1 2107361 {my ($tree) = @_; # Tree
52 1131074 50       1897163 @_ == 1 or confess;
53 1131074         17133893 my $n = $tree->keys->@*;
54 1131074 50       4613355 $n <= maximumNumberOfKeys+1 or confess "Keys";
55 1131074         1752788 $n == minimumNumberOfKeys
56             }
57              
58             sub root($) # Return the root node of a tree.
59 85     85 1 195 {my ($tree) = @_; # Tree
60 85 50       274 confess unless $tree;
61 85         1543 for(; $tree->up; $tree = $tree->up) {}
62 85         743 $tree
63             }
64              
65             sub leaf($) # Confirm that the tree is a leaf.
66 912539     912539 1 1294661 {my ($tree) = @_; # Tree
67 912539 50       1613842 @_ == 1 or confess;
68 912539         13949214 !scalar $tree->node->@* # No children so it must be a leaf
69             }
70              
71             sub reUp($$) #P Reconnect the children to their new parent.
72 115760     115760 1 553254 {my ($tree, $children) = @_; # Tree, children
73 115760 50       246929 @_ > 0 or confess;
74 115760 50       1745714 $tree->keys->@* <= maximumNumberOfKeys or confess "Keys";
75 115760         1825792 $_->up = $tree for @$children; # Connect child to parent
76             }
77              
78             sub splitFullNode($$$) #P Split a node if it is full.
79 1129141     1129141 1 2452970 {my ($isRoot, $isLeaf, $node) = @_; # Known to be the root if true, known to be a leaf if true, node to split
80 1129141 50       1965417 @_ == 3 or confess;
81              
82 1129141         1413144 if (1) # Check number of keys
83 1129141         17114941 {my $c = $node->keys->@*; # Number of keys
84 1129141 50       4569226 confess if $c > maximumNumberOfKeys; # Complain about over full nodes
85 1129141 100       1542704 return unless $c == maximumNumberOfKeys; # Only split full nodes
86             }
87              
88 122911   66     1892594 my ($p, $l, $r) = ($node->up // $node, new, new); # New child nodes
89 122911         7575042 $l->up = $r->up = $p; # Connect children to parent
90              
91 122911         2348867 my @k = $node->keys->@*;
92 122911         2292705 my @d = $node->data->@*;
93              
94 122911         595326 my $N = int maximumNumberOfNodes / 2; # Split points
95 122911 100       200139 my $n = maximumNumberOfKeys % 2 == 0 ? $N - 1 : $N - 2;
96              
97 122911         2148552 $l->keys = [@k[0..$n]]; # Split keys
98 122911         2264842 $l->data = [@d[0..$n]]; # Split data
99 122911         2271020 $r->keys = [@k[$n+2..$#k]];
100 122911         2255907 $r->data = [@d[$n+2..$#k]];
101              
102 122911 100       571898 if (!$isLeaf) # Not a leaf node
103 38112         582680 {my @n = $node->node->@*;
104 38112         745643 reUp $l, $l->node = [@n[0 ..$n+1]];
105 38112         1587144 reUp $r, $r->node = [@n[$n+2..$#n ]];
106             }
107              
108 122911 100       977896 if (!$isRoot) # Not a root node
109 115052         1770039 {my @n = $p->node->@*; # Insert new nodes in parent known to be not full
110 115052         621764 for my $i(keys @n) # Each parent node
111 215859 100       491837 {if ($n[$i] == $node) # Find the node that points from the parent to the current node
112 115052         1786396 {splice $p->keys->@*, $i, 0, $k[$n+1]; # Insert splitting key
113 115052         2206754 splice $p->data->@*, $i, 0, $d[$n+1]; # Insert data associated with splitting key
114 115052         2101610 splice $p->node->@*, $i, 1, $l, $r; # Insert offsets on either side of the splitting key
115 115052         2320267 return; #
116             }
117             }
118 0         0 confess "Should not happen";
119             }
120             else # Root node with single key after split
121 7859         133795 {$node->keys = [$k[$n+1]]; # Single key
122 7859         154533 $node->data = [$d[$n+1]]; # Data associated with single key
123 7859         145630 $node->node = [$l, $r]; # Nodes on either side of single key
124             }
125             }
126              
127             sub findAndSplit($$) #P Find a key in a tree splitting full nodes along the path to the key.
128 235001     235001 1 398306 {my ($root, $key) = @_; # Root of tree, key
129 235001 50       421616 @_ == 2 or confess;
130              
131 235001         286121 my $tree = $root; # Start at the root
132              
133 235001         3577955 splitFullNode 1, !scalar($tree->node->@*), $tree; # Split the root node if necessary
134              
135 235001         536444 for(0..999) # Step down through the tree
136 894190 50       13674830 {confess unless my @k = $tree->keys->@*; # We should have at least one key in the tree because we do a special case insert for an empty tree
137              
138 894190 100       5226460 if ($key < $k[0]) # Less than smallest key in node
139 341371 100       5224902 {return (-1, $tree, 0) unless my $n = $tree->node->[0];
140 259188         1161135 $tree = $n;
141 259188         420926 next;
142             }
143              
144 552819 100       1004550 if ($key > $k[-1]) # Greater than largest key in node
145 330467 100       5000598 {return (+1, $tree, $#k) unless my $n = $tree->node->[-1];
146 245422         1080547 $tree = $n;
147 245422         399992 next;
148             }
149              
150 222352         464166 for my $i(keys @k) # Search the keys in this node as greater than least key and less than largest key
151 553485         854888 {my $s = $key <=> $k[$i]; # Compare key
152 553485 100       1179756 if ($s == 0) # Found key
    100          
153 50         159 {return (0, $tree, $i);
154             }
155             elsif ($s < 0) # Less than current key
156 222302 100       3543224 {return (-1, $tree, $i) unless my $n = $tree->node->[$i]; # Step through if possible
157 154579         746297 $tree = $n; # Step
158 154579         314966 last;
159             }
160             }
161             }
162 659189         1080874 continue {splitFullNode 0, 0, $tree} # Split the node we have stepped to
163              
164 0         0 confess "Should not happen";
165             }
166              
167             sub find($$) # Find a key in a tree returning its associated data or undef if the key does not exist.
168 481951     481951 1 873908 {my ($root, $key) = @_; # Root of tree, key
169 481951 50       914546 @_ == 2 or confess;
170              
171 481951         620280 my $tree = $root; # Start at the root
172              
173 481951         856993 for(0..999) # Step down through the tree
174 1670462 100       25332438 {return undef unless my @k = $tree->keys->@*; # Empty node
175              
176 1668240 100       9671846 if ($key < $k[0]) # Less than smallest key in node
177 584667 100       8819752 {return undef unless $tree = $tree->node->[0];
178 486941         2345649 next;
179             }
180              
181 1083573 100       1748179 if ($key > $k[-1]) # Greater than largest key in node
182 549170 100       8366317 {return undef unless $tree = $tree->node->[-1];
183 445206         2174210 next;
184             }
185              
186 534403         1037977 for my $i(keys @k) # Search the keys in this node
187 1103376         1610814 {my $s = $key <=> $k[$i]; # Compare key
188 1103376 100       5238444 return $tree->data->[$i] if $s == 0; # Found key
189 861888 100       1512817 if ($s < 0) # Less than current key
190 292915 100       4664559 {return undef unless $tree = $tree->node->[$i];
191 256364         1421857 last;
192             }
193             }
194             }
195              
196 0         0 confess "Should not happen";
197             }
198              
199             sub indexInParent($) #P Get the index of a node in its parent.
200 405125     405125 1 584893 {my ($tree) = @_; # Tree
201 405125 50       751530 @_ == 1 or confess; confess unless my $p = $tree->up;
  405125 50       6271244  
202              
203 405125 100       7164216 my @n = $p->node->@*; for my $i(keys @n) {return $i if $n[$i] == $tree}
  405125         2035400  
  969626         2492516  
204 0         0 confess "Should not happen";
205             }
206              
207             sub fillFromLeftOrRight($$) #P Fill a node from the specified sibling.
208 72402     72402 1 139676 {my ($node, $dir) = @_; # Node to fill, node to fill from 0 for left or 1 for right
209 72402 50       140069 @_ == 2 or confess;
210              
211 72402 50       1168189 confess unless my $p = $node->up; # Parent of leaf
212 72402         376166 my $i = indexInParent $node; # Index of leaf in parent
213              
214 72402 100       151311 if ($dir) # Fill from right
215 9243 50       148790 {$i < $p->node->@* - 1 or confess; # Cannot fill from right
216 9243         181643 my $r = $p->node->[$i+1]; # Right sibling
217 9243         171540 push $node->keys->@*, $p->keys->[$i]; $p->keys->[$i] = shift $r->keys->@*; # Transfer key
  9243         194679  
218 9243         193488 push $node->data->@*, $p->data->[$i]; $p->data->[$i] = shift $r->data->@*; # Transfer data
  9243         186821  
219 9243 100       69554 if (!leaf $node) # Transfer node if not a leaf
220 4211         84929 {push $node->node->@*, shift $r->node->@*;
221 4211         90023 $node->node->[-1]->up = $node;
222             }
223             }
224             else # Fill from left
225 63159 50       141108 {$i > 0 or confess; # Cannot fill from left
226 63159         106232 my $I = $i-1;
227 63159         1006859 my $n = $p->node->[$I]; # Left sibling
228 63159         1125732 my $k = $p->keys; my $d = $p->data;
  63159         1099819  
229 63159         1082127 unshift $node->keys->@*, $k->[$I]; $k->[$I] = pop $n->keys->@*; # Transfer key
  63159         1186425  
230 63159         1148214 unshift $node->data->@*, $d->[$I]; $d->[$I] = pop $n->data->@*; # Transfer data
  63159         1145287  
231 63159 100       319977 if (!leaf $node) # Transfer node if not a leaf
232 22320         426189 {unshift $node->node->@*, pop $n->node->@*;
233 22320         457070 $node->node->[0]->up = $node;
234             }
235             }
236             }
237              
238             sub mergeWithLeftOrRight($$) #P Merge two adjacent nodes.
239 113244     113244 1 205123 {my ($n, $dir) = @_; # Node to merge into, node to merge is on right if 1 else left
240 113244 50       248447 @_ == 2 or confess;
241              
242 113244 50       185608 confess unless halfFull($n); # Confirm leaf is half full
243 113244 50       1802229 confess unless my $p = $n->up; # Parent of leaf
244 113244 50 66     534799 confess if halfFull($p) and $p->up; # Parent must have more than the minimum number of keys because we need to remove one unless it is the root of the tree
245              
246 113244         230021 my $i = indexInParent $n; # Index of leaf in parent
247              
248 113244 100       229442 if ($dir) # Merge with right hand sibling
249 22489 50       355698 {$i < $p->node->@* - 1 or confess; # Cannot fill from right
250 22489         120856 my $I = $i+1;
251 22489         334727 my $r = $p->node->[$I]; # Leaf on right
252 22489 50       108864 confess unless halfFull($r); # Confirm right leaf is half full
253 22489         355449 push $n->keys->@*, splice($p->keys->@*, $i, 1), $r->keys->@*; # Transfer keys
254 22489         544282 push $n->data->@*, splice($p->data->@*, $i, 1), $r->data->@*; # Transfer data
255 22489 100       217001 if (!leaf $n) # Children of merged node
256 7320         142910 {push $n->node->@*, $r->node->@*; # Children of merged node
257 7320         151191 reUp $n, $r->node; # Update parent of children of right node
258             }
259 22489         555570 splice $p->node->@*, $I, 1; # Remove link from parent to right child
260             }
261             else # Merge with left hand sibling
262 90755 50       184318 {$i > 0 or confess; # Cannot fill from left
263 90755         133087 my $I = $i-1;
264 90755         1414975 my $l = $p->node->[$I]; # Node on left
265 90755 50       411319 confess unless halfFull($l); # Confirm right leaf is half full
266 90755         1416810 unshift $n->keys->@*, $l->keys->@*, splice $p->keys->@*, $I, 1; # Transfer keys
267 90755         2141558 unshift $n->data->@*, $l->data->@*, splice $p->data->@*, $I, 1; # Transfer data
268 90755 100       806070 if (!leaf $n) # Children of merged node
269 24576         467953 {unshift $n->node->@*, $l->node->@*; # Children of merged node
270 24576         498758 reUp $n, $l->node; # Update parent of children of left node
271             }
272 90755         2099603 splice $p->node->@*, $I, 1; # Remove link from parent to left child
273             }
274             }
275              
276             sub merge($) #P Merge the current node with its sibling.
277 185646     185646 1 328164 {my ($tree) = @_; # Tree
278 185646 100       331848 if (my $i = indexInParent $tree) # Merge with left node
279 153914         2425360 {my $l = $tree->up->node->[$i-1]; # Left node
280 153914 50       3008710 if (halfFull(my $r = $tree))
281 153914 100       285914 {$l->halfFull ? mergeWithLeftOrRight $r, 0 : fillFromLeftOrRight $r, 0; # Merge as left and right nodes are half full
282             }
283             }
284             else
285 31732         498953 {my $r = $tree->up->node->[1]; # Right node
286 31732 50       625728 if (halfFull(my $l = $tree))
287 31732 100       59383 {halfFull($r) ? mergeWithLeftOrRight $l, 1 : fillFromLeftOrRight $l, 1; # Merge as left and right nodes are half full
288             }
289             }
290             }
291              
292             sub mergeOrFill($) #P Make a node larger than a half node.
293 398702     398702 1 1497616 {my ($tree) = @_; # Tree
294 398702 50       704833 @_ == 1 or confess;
295              
296 398702 100       648680 return unless halfFull($tree); # No need to merge of if not a half node
297 193286 50       3077834 confess unless my $p = $tree->up; # Parent exists
298              
299 193286 100 100     3442733 if ($p->up) # Merge or fill parent which is not the root
    100 100        
300 163134         801174 {__SUB__->($p);
301 163134         1354708 merge($tree);
302             }
303             elsif ($p->keys->@* == 1 and halfFull(my $l = $p->node->[0]) # Parent is the root and it only has one key - merge into the child if possible
304             and halfFull(my $r = $p->node->[1]))
305 7640         131425 {$p->keys = $tree->keys = [$l->keys->@*, $p->keys->@*, $r->keys->@*]; # Merge in place to retain addressability
306 7640         216553 $p->data = $tree->data = [$l->data->@*, $p->data->@*, $r->data->@*];
307 7640         202720 $p->node = $tree->node = [$l->node->@*, $r->node->@*];
308              
309 7640         181392 reUp $p, $p->node; # Reconnect children to parent
310             }
311             else # Parent is the root but it has too may keys to merge into both sibling so merge with a sibling if possible
312 22512         424751 {merge($tree);
313             }
314             }
315              
316             sub leftMost($) # Return the left most node below the specified one.
317 84314     84314 1 441227 {my ($tree) = @_; # Tree
318 84314         180388 for(0..999) # Step down through tree
319 136149 100       368722 {return $tree if leaf $tree; # We are on a leaf so we have arrived at the left most node
320 51835         976739 $tree = $tree->node->[0]; # Go left
321             }
322 0         0 confess "Should not happen";
323             }
324              
325             sub rightMost($) # Return the right most node below the specified one.
326 46451     46451 1 243032 {my ($tree) = @_; # Tree
327 46451         117261 for(0..999) # Step down through tree
328 72061 100       192481 {return $tree if leaf $tree; # We are on a leaf so we have arrived at the left most node
329 25610         490189 $tree = $tree->node->[-1]; # Go right
330             }
331 0         0 confess "Should not happen";
332             }
333              
334             sub height($) # Return the height of the tree.
335 476     476 1 869 {my ($tree) = @_; # Tree
336 476         914 for my $n(0..999) # Step down through tree
337 2291 100       8754 {if (leaf $tree) # We are on a leaf
338 476 100       9155 {return $n + 1 if $tree->keys->@*; # We are in a partially full leaf
339 5         98 return $n; # We are on the root and it is empty
340             }
341 1815         34056 $tree = $tree->node->[0];
342             }
343 0         0 confess "Should not happen";
344             }
345              
346             sub depth($) # Return the depth of a node within a tree.
347 62     62 1 327 {my ($tree) = @_; # Tree
348 62 100 100     969 return 0 if !$tree->up and !$tree->keys->@*; # We are at the root and it is empty
349 61         452 for my $n(1..999) # Step down through tree
350 125 100       2104 {return $n unless $tree->up; # We are at the root
351 64         1145 $tree = $tree->up;
352             }
353 0         0 confess "Should not happen";
354             }
355              
356             sub deleteLeafKey($$) #P Delete a key in a leaf.
357 240493     240493 1 546983 {my ($tree, $i) = @_; # Tree, index to delete at
358 240493 50       489018 @_ == 2 or confess;
359 240493 50       391581 confess "Not a leaf" unless leaf $tree;
360 240493         4471033 my $key = $tree->keys->[$i];
361 240493 100       4270632 mergeOrFill $tree if $tree->up; # Merge and fill unless we are on the root and the root is a leaf
362 240493         4561535 my $k = $tree->keys;
363 240493         1078895 for my $j(keys @$k) # Search for key to delete
364 490896 100       1017054 {if ($$k[$j] == $key)
365 240493         3735296 {splice $tree->keys->@*, $j, 1; # Remove keys
366 240493         4309442 splice $tree->data->@*, $j, 1; # Remove data
367 240493         1104330 return;
368             }
369             }
370             }
371              
372             sub deleteKey($$) #P Delete a key.
373 240493     240493 1 401329 {my ($tree, $i) = @_; # Tree, index to delete at
374 240493 50       474153 @_ == 2 or confess;
375 240493 100       433231 if (leaf $tree) # Delete from a leaf
    100          
376 127494         743344 {deleteLeafKey($tree, $i);
377             }
378             elsif ($i > 0) # Delete from a node
379 45364         886864 {my $l = rightMost $tree->node->[$i]; # Find previous node
380 45364         908635 splice $tree->keys->@*, $i, 1, $l->keys->[-1];
381 45364         981993 splice $tree->data->@*, $i, 1, $l->data->[-1];
382 45364         929383 deleteLeafKey $l, -1 + scalar $l->keys->@*; # Remove leaf key
383             }
384             else # Delete from a node
385 67635         1303159 {my $r = leftMost $tree->node->[1]; # Find previous node
386 67635         1328377 splice $tree->keys->@*, 0, 1, $r->keys->[0];
387 67635         1425570 splice $tree->data->@*, 0, 1, $r->data->[0];
388 67635         490124 deleteLeafKey $r, 0; # Remove leaf key
389             }
390             }
391              
392             sub delete($$) # Find a key in a tree, delete it and return any associated data.
393 240493     240493 1 478204 {my ($root, $key) = @_; # Tree root, key
394 240493 50       507361 @_ == 2 or confess;
395              
396 240493         328735 my $tree = $root;
397 240493         466647 for (0..999)
398 750505         12677741 {my $k = $tree->keys;
399              
400 750505 100       3554220 if ($key < $$k[0]) # Less than smallest key in node
    100          
401 204939 50       3079699 {return undef unless $tree = $tree->node->[0];
402             }
403             elsif ($key > $$k[-1]) # Greater than largest key in node
404 189405 50       2866901 {return undef unless $tree = $tree->node->[-1];
405             }
406             else
407 356161         690253 {for my $i(keys @$k) # Search the keys in this node
408 654984 100       1507385 {if ((my $s = $key <=> $$k[$i]) == 0) # Delete found key
    100          
409 240493         3768641 {my $d = $tree->data->[$i]; # Save data
410 240493         1169212 deleteKey $tree, $i; # Delete the key
411 240493         4028396 return $d; # Return data associated with key
412             }
413             elsif ($s < 0) # Less than current key
414 115668 50       1846340 {return undef unless $tree = $tree->node->[$i];
415 115668         629283 last;
416             }
417             }
418             }
419             }
420 0         0 confess "Should not happen";
421             }
422              
423             sub insert($$$) # Insert the specified key and data into a tree.
424 243524     243524 1 586996 {my ($tree, $key, $data) = @_; # Tree, key, data
425 243524 50       503555 @_ == 3 or confess;
426              
427 243524 100 100     3709764 if (!(my $n = $tree->keys->@*)) # Empty tree
    100          
428 2296         49433 {push $tree->keys->@*, $key;
429 2296         44998 push $tree->data->@*, $data;
430 2296         47322 return $tree;
431             }
432             elsif ($n < maximumNumberOfKeys and $tree->node->@* == 0) # Node is root with no children and room for one more key
433 6227         119193 {my $k = $tree->keys;
434 6227         29579 for my $i(reverse keys @$k) # Each key - in reverse due to the preponderance of already sorted data
435 10234 50       37129 {if ((my $s = $key <=> $$k[$i]) == 0) # Key already present
    100          
436 0         0 {$tree->data->[$i]= $data;
437 0         0 return;
438             }
439             elsif ($s > 0) # Insert before greatest smaller key
440 3902         6679 {my $I = $i + 1;
441 3902         64148 splice $tree->keys->@*, $I, 0, $key;
442 3902         73737 splice $tree->data->@*, $I, 0, $data;
443 3902         79839 return;
444             }
445             }
446 2325         37782 unshift $tree->keys->@*, $key; # Insert the key at the start of the block because it is less than all the other keys in the block
447 2325         44867 unshift $tree->data->@*, $data;
448             }
449             else # Insert node
450 235001         1324241 {my ($compare, $node, $index) = findAndSplit $tree, $key; # Check for existing key
451              
452 235001 100       1597346 if ($compare == 0) # Found an equal key whose data we can update
453 50         870 {$node->data->[$index] = $data;
454             }
455             else # We have room for the insert
456 234951 100       485971 {++$index if $compare > 0; # Position at which to insert new key
457 234951         3659330 splice $node->keys->@*, $index, 0, $key;
458 234951         4366394 splice $node->data->@*, $index, 0, $data;
459 234951         1104666 splitFullNode 0, 1, $node # Split if the leaf is full to force keys up the tree
460             }
461             }
462             }
463              
464             sub iterator($) # Make an iterator for a tree.
465 263     263 1 801 {my ($tree) = @_; # Tree
466 263 50       919 @_ == 1 or confess;
467 263         1396 my $i = genHash(__PACKAGE__.'::Iterator', # Iterator
468             tree => $tree, # Tree we are iterating over
469             node => $tree, # Current node within tree
470             pos => undef, # Current position within node
471             key => undef, # Key at this position
472             data => undef, # Data at this position
473             count => 0, # Counter
474             more => 1, # Iteration not yet finished
475             );
476 263         25916 $i->next; # First element if any
477 263         11094 $i # Iterator
478             }
479              
480             sub Tree::Multi::Iterator::next($) # Find the next key.
481 33522     33522   162610 {my ($iter) = @_; # Iterator
482 33522 50       68980 @_ == 1 or confess;
483 33522 50       535956 confess unless my $C = $iter->node; # Current node required
484              
485 33522         622182 ++$iter->count; # Count the calls to the iterator
486              
487             my $new = sub # Load iterator with latest position
488 33259     33259   208861 {my ($node, $pos) = @_; # Parameters
489 33259         537014 $iter->node = $node;
490 33259   100     661711 $iter->pos = $pos //= 0;
491 33259         589885 $iter->key = $node->keys->[$pos];
492 33259         1139938 $iter->data = $node->data->[$pos]
493 33522         195545 };
494              
495 33522     263   77208 my $done = sub {$iter->more = undef}; # The tree has been completely traversed
  263         4444  
496              
497 33522 100       550483 if (!defined($iter->pos)) # Initial descent
498 263         5396 {my $l = $C->node->[0];
499 263 50       2143 return $l ? &$new($l->leftMost) : $C->keys->@* ? &$new($C) : &$done; # Start node or done if empty tree
    100          
500             }
501              
502             my $up = sub # Iterate up to next node that has not been visited
503 16671     16671   318094 {for(my $n = $C; my $p = $n->up; $n = $p)
504 31936         424883 {my $i = indexInParent $n;
505 31936 100       520120 return &$new($p, $i) if $i < $p->keys->@*;
506             }
507 263         6164 &$done # No nodes not visited
508 33259         190998 };
509              
510 33259         543171 my $i = ++$iter->pos;
511 33259 100       138324 if (leaf $C) # Leaf
512 16851 100       326850 {$i < $C->keys->@* ? &$new($C, $i) : &$up;
513             }
514             else # Node
515 16408         313674 {&$new($C->node->[$i]->leftMost)
516             }
517             }
518              
519             sub reverseIterator($) # Create a reverse iterator for a tree.
520 65     65 1 188 {my ($tree) = @_; # Tree
521 65 50       238 @_ == 1 or confess;
522 65         242 my $i = genHash(__PACKAGE__.'::ReverseIterator', # Iterator
523             tree => root($tree), # Tree we are iterating over
524             node => $tree, # Current node within tree
525             pos => undef, # Current position within node
526             key => undef, # Key at this position
527             data => undef, # Data at this position
528             count => 0, # Counter
529             less => 1, # Iteration not yet finished
530             );
531 65         6618 $i->prev; # Last element if any
532 65         2832 $i # Iterator
533             }
534              
535             sub Tree::Multi::ReverseIterator::prev($) # Find the previous key.
536 2210     2210   10347 {my ($iter) = @_; # Iterator
537 2210 50       4668 @_ == 1 or confess;
538 2210 50       34926 confess unless my $C = $iter->node; # Current node required
539              
540 2210         42202 ++$iter->count; # Count the calls to the iterator
541              
542             my $new = sub # Load iterator with latest position
543 2145     2145   8723 {my ($node, $pos) = @_; # Parameters
544 2145         34723 $iter->node = $node;
545 2145   100     41850 $iter->pos = $pos //= ($node->keys->@* - 1);
546 2145         57191 $iter->key = $node->keys->[$pos];
547 2145         72951 $iter->data = $node->data->[$pos]
548 2210         13027 };
549              
550 2210     65   5281 my $done = sub {$iter->less = undef}; # The tree has been completely traversed
  65         1080  
551              
552 2210 100       36386 if (!defined($iter->pos)) # Initial descent
553 65         1328 {my $l = $C->node->[-1];
554 65 50       596 return $l ? &$new($l->rightMost) : $C->keys->@* ? &$new($C) : &$done; # Start node or done if empty tree
    100          
555 0         0 return;
556             }
557              
558             my $up = sub # Iterate up to next node that has not been visited
559 1088     1088   17634 {for(my $n = $C; my $p = $n->up; $n = $p)
560 1897         9178 {my $i = indexInParent $n;
561 1897 100       18163 return &$new($p, $i-1) if $i > 0;
562             }
563 65         408 &$done # No nodes not visited
564 2145         12707 };
565              
566 2145         35436 my $i = $iter->pos;
567 2145 100       9045 if (leaf $C) # Leaf
568 1122 100       6642 {$i > 0 ? &$new($C, $i-1) : &$up;
569             }
570             else # Node
571 1023 50       20355 {$i >= 0 ? &$new($C->node->[$i]->rightMost) : &$up
572             }
573             }
574              
575             sub flat($@) # Print the keys in a tree from left right to make it easier to visualize the structure of the tree.
576 4     4 1 12 {my ($tree, @title) = @_; # Tree, title
577 4 50       12 confess unless $tree;
578 4         23 my @s; # Print
579             my $D; # Deepest
580 4         16 for(my $i = iterator root $tree; $i->more; $i->next) # Traverse tree
581 53         2824 {my $d = depth $i->node;
582 53 100 100     375 $D = $d unless $D and $D > $d;
583 53   100     120 $s[$d] //= '';
584 53         866 $s[$d] .= " ".$i->key; # Add key at appropriate depth
585 53         231 my $l = length $s[$d];
586 53         100 for my $j(0..$D) # Pad all strings to the current position
587 175   100     359 {my $s = $s[$j] //= '';
588 175 100       551 $s[$j] = substr($s.(' 'x999), 0, $l) if length($s) < $l;
589             }
590             }
591 4         50 for my $i(keys @s) # Clean up trailing blanks so that tests are not affected by spurious white space mismatches
592 14         23 {$s[$i] =~ s/\s+\n/\n/gs;
593 14         67 $s[$i] =~ s/\s+\Z//gs;
594             }
595 4 50       12 unshift @s, join(' ', @title) if @title; # Add title
596 4         102 join "\n", @s, '';
597             }
598              
599             sub print($;$) # Print the keys in a tree optionally marking the active key.
600 4     4 1 14 {my ($tree, $i) = @_; # Tree, optional index of active key
601 4 50       12 confess unless $tree;
602 4         11 my @s; # Print
603              
604             my $print = sub # Print a node
605 112     112   192 {my ($t, $in) = @_;
606 112 50 33     1895 return unless $t and $t->keys and $t->keys->@*;
      33        
607              
608 112         2727 my @t = (' 'x$in); # Print keys staring the active key if known
609 112         1778 for my $j(keys $t->keys->@*)
610 557         9105 {push @t, $t->keys->[$j];
611 557 0 33     2670 push @t, '<=' if defined($i) and $i == $j and $tree == $t;
      33        
612             }
613 112         362 push @s, join ' ', @t; # Details of one node
614              
615 112 50       1781 if (my $nodes = $t->node) # Each key
616 112         775 {__SUB__->($_, $in+1) for $nodes->@*;
617             }
618 4         33 };
619              
620 4         21 &$print(root($tree), 0); # Print tree
621              
622 4         171 join "\n", @s, ''
623             }
624              
625             sub size($) # Count the number of keys in a tree.
626 11     11 1 53 {my ($tree) = @_; # Tree
627 11 50       33 @_ == 1 or confess;
628 11         20 my $n = 0; # Print
629              
630             my $count = sub # Print a node
631 55     55   93 {my ($t) = @_;
632 55 100 33     952 return unless $t and $t->keys and my @k = $t->keys->@*;
      66        
633 54         1279 $n += @k;
634 54 50       844 if (my $nodes = $t->node) # Each key
635 54         334 {__SUB__->($_) for $nodes->@*;
636             }
637 11         60 };
638              
639 11         33 &$count(root $tree); # Count nodes in tree
640              
641 11         132 $n;
642             }
643              
644             #d
645             #-------------------------------------------------------------------------------
646             # Export - eeee
647             #-------------------------------------------------------------------------------
648              
649 1     1   14 use Exporter qw(import);
  1         3  
  1         41  
650              
651 1     1   6 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         2  
  1         452  
652              
653             @ISA = qw(Exporter);
654             @EXPORT = qw();
655             @EXPORT_OK = qw(
656             );
657             %EXPORT_TAGS = (all=>[@EXPORT, @EXPORT_OK]);
658              
659             # podDocumentation
660             =pod
661              
662             =encoding utf-8
663              
664             =head1 Name
665              
666             Tree::Multi - Multi-way tree in Pure Perl with an even or odd number of keys per node.
667              
668             =head1 Synopsis
669              
670             Construct and query a multi-way tree in B<100%> Pure Perl with a choice of an
671             odd or an even numbers of keys per node:
672              
673             local $Tree::Multi::numberOfKeysPerNode = 4; # Number of keys per node - can be even
674              
675             my $t = Tree::Multi::new; # Construct tree
676             $t->insert($_, 2 * $_) for reverse 1..32; # Load tree in reverse
677              
678             is_deeply $t->print, <
679             15 21 27
680             3 6 9 12
681             1 2
682             4 5
683             7 8
684             10 11
685             13 14
686             18
687             16 17
688             19 20
689             24
690             22 23
691             25 26
692             30
693             28 29
694             31 32
695             END
696              
697             ok $t->height == 3; # Height
698              
699             ok $t->find (16) == 32; # Find by key
700             $t->delete(16); # Delete a key
701             ok !$t->find (16); # Key no longer present
702              
703              
704             ok $t->find (17) == 34; # Find by key
705             my @k;
706             for(my $i = $t->iterator; $i->more; $i->next) # Iterator
707             {push @k, $i->key unless $i->key == 17;
708             }
709              
710             $t->delete($_) for @k; # Delete
711              
712             ok $t->find(17) == 34 && $t->size == 1; # Size
713              
714             =head1 Description
715              
716             Multi-way tree in Pure Perl with an even or odd number of keys per node.
717              
718              
719             Version "20210614".
720              
721              
722             The following sections describe the methods in each functional area of this
723             module. For an alphabetic listing of all methods by name see L.
724              
725              
726              
727             =head1 Multi-way Tree
728              
729             Create and use a multi-way tree.
730              
731             =head2 root($tree)
732              
733             Return the root node of a tree.
734              
735             Parameter Description
736             1 $tree Tree
737              
738             B
739              
740              
741             local $numberOfKeysPerNode = 3; my $N = 13; my $t = new;
742              
743             for my $n(1..$N)
744             {$t->insert($n, $n);
745             }
746              
747             ok T($t, <
748             4 8
749             2
750             1
751             3
752             6
753             5
754             7
755             10 12
756             9
757             11
758             13
759             END
760              
761             is_deeply $t->leftMost ->keys, [1];
762             is_deeply $t->rightMost->keys, [13];
763             ok $t->leftMost ->leaf;
764             ok $t->rightMost->leaf;
765              
766             ok $t->root == $t; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
767              
768              
769              
770             =head2 leaf($tree)
771              
772             Confirm that the tree is a leaf.
773              
774             Parameter Description
775             1 $tree Tree
776              
777             B
778              
779              
780             local $numberOfKeysPerNode = 3; my $N = 13; my $t = new;
781              
782             for my $n(1..$N)
783             {$t->insert($n, $n);
784             }
785              
786             ok T($t, <
787             4 8
788             2
789             1
790             3
791             6
792             5
793             7
794             10 12
795             9
796             11
797             13
798             END
799              
800             is_deeply $t->leftMost ->keys, [1];
801             is_deeply $t->rightMost->keys, [13];
802              
803             ok $t->leftMost ->leaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
804              
805              
806             ok $t->rightMost->leaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
807              
808             ok $t->root == $t;
809              
810              
811             =head2 find($root, $key)
812              
813             Find a key in a tree returning its associated data or undef if the key does not exist.
814              
815             Parameter Description
816             1 $root Root of tree
817             2 $key Key
818              
819             B
820              
821              
822             local $Tree::Multi::numberOfKeysPerNode = 4; # Number of keys per node - can be even
823              
824             my $t = Tree::Multi::new; # Construct tree
825             $t->insert($_, 2 * $_) for reverse 1..32; # Load tree in reverse
826              
827             T($t, <
828             17 25
829             9 13
830             3 5 7
831             1 2
832             4
833             6
834             8
835             11
836             10
837             12
838             15
839             14
840             16
841             21
842             19
843             18
844             20
845             23
846             22
847             24
848             29
849             27
850             26
851             28
852             31
853             30
854             32
855             END
856              
857             ok $t->size == 32; # Size
858             ok $t->height == 4; # Height
859             ok $t->delete(16) == 2 * 16; # Delete a key
860              
861             ok !$t->find (16); # Key no longer present # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
862              
863              
864             ok $t->find (17) == 34; # Find by key # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
865              
866              
867             my @k;
868             for(my $i = $t->iterator; $i->more; $i->next) # Iterator
869             {push @k, $i->key unless $i->key == 17;
870             }
871              
872             ok $t->delete($_) == 2 * $_ for @k; # Delete
873              
874              
875             ok $t->find(17) == 34 && $t->size == 1; # Size # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
876              
877              
878             local $Tree::Multi::numberOfKeysPerNode = 3; # Number of keys per node - can be even
879              
880             my $t = Tree::Multi::new; # Construct tree
881             $t->insert($_, $_) for 1..8;
882              
883             T($t, <
884              
885             4
886             2 6
887             1 3 5 7 8
888             END
889              
890             local $Tree::Multi::numberOfKeysPerNode = 14; # Number of keys per node - can be even
891              
892             my $t = Tree::Multi::new; # Construct tree
893             $t->insert($_, $_) for 1..15;
894              
895             T($t, <
896              
897             8
898             1 2 3 4 5 6 7 9 10 11 12 13 14 15
899             END
900              
901              
902             =head2 leftMost($tree)
903              
904             Return the left most node below the specified one.
905              
906             Parameter Description
907             1 $tree Tree
908              
909             B
910              
911              
912             local $numberOfKeysPerNode = 3; my $N = 13; my $t = new;
913              
914             for my $n(1..$N)
915             {$t->insert($n, $n);
916             }
917              
918             ok T($t, <
919             4 8
920             2
921             1
922             3
923             6
924             5
925             7
926             10 12
927             9
928             11
929             13
930             END
931              
932              
933             is_deeply $t->leftMost ->keys, [1]; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
934              
935             is_deeply $t->rightMost->keys, [13];
936              
937             ok $t->leftMost ->leaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
938              
939             ok $t->rightMost->leaf;
940             ok $t->root == $t;
941              
942              
943             =head2 rightMost($tree)
944              
945             Return the right most node below the specified one.
946              
947             Parameter Description
948             1 $tree Tree
949              
950             B
951              
952              
953             local $numberOfKeysPerNode = 3; my $N = 13; my $t = new;
954              
955             for my $n(1..$N)
956             {$t->insert($n, $n);
957             }
958              
959             ok T($t, <
960             4 8
961             2
962             1
963             3
964             6
965             5
966             7
967             10 12
968             9
969             11
970             13
971             END
972              
973             is_deeply $t->leftMost ->keys, [1];
974              
975             is_deeply $t->rightMost->keys, [13]; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
976              
977             ok $t->leftMost ->leaf;
978              
979             ok $t->rightMost->leaf; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
980              
981             ok $t->root == $t;
982              
983              
984             =head2 height($tree)
985              
986             Return the height of the tree.
987              
988             Parameter Description
989             1 $tree Tree
990              
991             B
992              
993              
994             local $Tree::Multi::numberOfKeysPerNode = 3;
995              
996             my $t = new; ok $t->height == 0; ok $t->leftMost->depth == 0; ok $t->size == 0; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
997              
998              
999             $t->insert(1, 1); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 1; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1000              
1001              
1002             $t->insert(2, 2); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 2; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1003              
1004              
1005             $t->insert(3, 3); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 3; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1006              
1007              
1008             $t->insert(4, 4); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 4; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1009              
1010              
1011             $t->insert(5, 5); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 5; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1012              
1013              
1014             $t->insert(6, 6); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 6; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1015              
1016              
1017             $t->insert(7, 7); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 7; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1018              
1019              
1020             $t->insert(8, 8); ok $t->height == 3; ok $t->leftMost->depth == 3; ok $t->size == 8; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1021              
1022              
1023             T($t, <
1024              
1025             4
1026             2 6
1027             1 3 5 7 8
1028             END
1029              
1030              
1031              
1032             =head2 depth($tree)
1033              
1034             Return the depth of a node within a tree.
1035              
1036             Parameter Description
1037             1 $tree Tree
1038              
1039             B
1040              
1041              
1042             local $Tree::Multi::numberOfKeysPerNode = 3;
1043              
1044             my $t = new; ok $t->height == 0; ok $t->leftMost->depth == 0; ok $t->size == 0; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1045              
1046              
1047             $t->insert(1, 1); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 1; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1048              
1049              
1050             $t->insert(2, 2); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 2; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1051              
1052              
1053             $t->insert(3, 3); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 3; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1054              
1055              
1056             $t->insert(4, 4); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 4; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1057              
1058              
1059             $t->insert(5, 5); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 5; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1060              
1061              
1062             $t->insert(6, 6); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 6; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1063              
1064              
1065             $t->insert(7, 7); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 7; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1066              
1067              
1068             $t->insert(8, 8); ok $t->height == 3; ok $t->leftMost->depth == 3; ok $t->size == 8; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1069              
1070              
1071             T($t, <
1072              
1073             4
1074             2 6
1075             1 3 5 7 8
1076             END
1077              
1078              
1079              
1080             =head2 delete($root, $key)
1081              
1082             Find a key in a tree, delete it and return any associated data.
1083              
1084             Parameter Description
1085             1 $root Tree root
1086             2 $key Key
1087              
1088             B
1089              
1090              
1091             local $Tree::Multi::numberOfKeysPerNode = 4; # Number of keys per node - can be even
1092              
1093             my $t = Tree::Multi::new; # Construct tree
1094             $t->insert($_, 2 * $_) for reverse 1..32; # Load tree in reverse
1095              
1096             T($t, <
1097             17 25
1098             9 13
1099             3 5 7
1100             1 2
1101             4
1102             6
1103             8
1104             11
1105             10
1106             12
1107             15
1108             14
1109             16
1110             21
1111             19
1112             18
1113             20
1114             23
1115             22
1116             24
1117             29
1118             27
1119             26
1120             28
1121             31
1122             30
1123             32
1124             END
1125              
1126             ok $t->size == 32; # Size
1127             ok $t->height == 4; # Height
1128              
1129             ok $t->delete(16) == 2 * 16; # Delete a key # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1130              
1131             ok !$t->find (16); # Key no longer present
1132             ok $t->find (17) == 34; # Find by key
1133              
1134             my @k;
1135             for(my $i = $t->iterator; $i->more; $i->next) # Iterator
1136             {push @k, $i->key unless $i->key == 17;
1137             }
1138              
1139              
1140             ok $t->delete($_) == 2 * $_ for @k; # Delete # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1141              
1142              
1143             ok $t->find(17) == 34 && $t->size == 1; # Size
1144              
1145             local $Tree::Multi::numberOfKeysPerNode = 3; # Number of keys per node - can be even
1146              
1147             my $t = Tree::Multi::new; # Construct tree
1148             $t->insert($_, $_) for 1..8;
1149              
1150             T($t, <
1151              
1152             4
1153             2 6
1154             1 3 5 7 8
1155             END
1156              
1157             local $Tree::Multi::numberOfKeysPerNode = 14; # Number of keys per node - can be even
1158              
1159             my $t = Tree::Multi::new; # Construct tree
1160             $t->insert($_, $_) for 1..15;
1161              
1162             T($t, <
1163              
1164             8
1165             1 2 3 4 5 6 7 9 10 11 12 13 14 15
1166             END
1167              
1168              
1169             =head2 insert($tree, $key, $data)
1170              
1171             Insert the specified key and data into a tree.
1172              
1173             Parameter Description
1174             1 $tree Tree
1175             2 $key Key
1176             3 $data Data
1177              
1178             B
1179              
1180              
1181             local $Tree::Multi::numberOfKeysPerNode = 4; # Number of keys per node - can be even
1182              
1183             my $t = Tree::Multi::new; # Construct tree
1184              
1185             $t->insert($_, 2 * $_) for reverse 1..32; # Load tree in reverse # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1186              
1187              
1188             T($t, <
1189             17 25
1190             9 13
1191             3 5 7
1192             1 2
1193             4
1194             6
1195             8
1196             11
1197             10
1198             12
1199             15
1200             14
1201             16
1202             21
1203             19
1204             18
1205             20
1206             23
1207             22
1208             24
1209             29
1210             27
1211             26
1212             28
1213             31
1214             30
1215             32
1216             END
1217              
1218             ok $t->size == 32; # Size
1219             ok $t->height == 4; # Height
1220             ok $t->delete(16) == 2 * 16; # Delete a key
1221             ok !$t->find (16); # Key no longer present
1222             ok $t->find (17) == 34; # Find by key
1223              
1224             my @k;
1225             for(my $i = $t->iterator; $i->more; $i->next) # Iterator
1226             {push @k, $i->key unless $i->key == 17;
1227             }
1228              
1229             ok $t->delete($_) == 2 * $_ for @k; # Delete
1230              
1231             ok $t->find(17) == 34 && $t->size == 1; # Size
1232              
1233             local $Tree::Multi::numberOfKeysPerNode = 3; # Number of keys per node - can be even
1234              
1235             my $t = Tree::Multi::new; # Construct tree
1236              
1237             $t->insert($_, $_) for 1..8; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1238              
1239              
1240             T($t, <
1241              
1242             4
1243             2 6
1244             1 3 5 7 8
1245             END
1246              
1247             local $Tree::Multi::numberOfKeysPerNode = 14; # Number of keys per node - can be even
1248              
1249             my $t = Tree::Multi::new; # Construct tree
1250              
1251             $t->insert($_, $_) for 1..15; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1252              
1253              
1254             T($t, <
1255              
1256             8
1257             1 2 3 4 5 6 7 9 10 11 12 13 14 15
1258             END
1259              
1260              
1261             =head2 iterator($tree)
1262              
1263             Make an iterator for a tree.
1264              
1265             Parameter Description
1266             1 $tree Tree
1267              
1268             B
1269              
1270              
1271             local $numberOfKeysPerNode = 3; my $N = 256; my $e = 0; my $t = new;
1272              
1273             for my $n(0..$N)
1274             {$t->insert($n, $n);
1275              
1276             my @n; for(my $i = $t->iterator; $i->more; $i->next) {push @n, $i->key} # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1277              
1278             ++$e unless dump(\@n) eq dump [0..$n];
1279             }
1280              
1281             is_deeply $e, 0;
1282              
1283             local $Tree::Multi::numberOfKeysPerNode = 4; # Number of keys per node - can be even
1284              
1285             my $t = Tree::Multi::new; # Construct tree
1286             $t->insert($_, 2 * $_) for reverse 1..32; # Load tree in reverse
1287              
1288             T($t, <
1289             17 25
1290             9 13
1291             3 5 7
1292             1 2
1293             4
1294             6
1295             8
1296             11
1297             10
1298             12
1299             15
1300             14
1301             16
1302             21
1303             19
1304             18
1305             20
1306             23
1307             22
1308             24
1309             29
1310             27
1311             26
1312             28
1313             31
1314             30
1315             32
1316             END
1317              
1318             ok $t->size == 32; # Size
1319             ok $t->height == 4; # Height
1320             ok $t->delete(16) == 2 * 16; # Delete a key
1321             ok !$t->find (16); # Key no longer present
1322             ok $t->find (17) == 34; # Find by key
1323              
1324             my @k;
1325              
1326             for(my $i = $t->iterator; $i->more; $i->next) # Iterator # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1327              
1328             {push @k, $i->key unless $i->key == 17;
1329             }
1330              
1331             ok $t->delete($_) == 2 * $_ for @k; # Delete
1332              
1333             ok $t->find(17) == 34 && $t->size == 1; # Size
1334              
1335             local $Tree::Multi::numberOfKeysPerNode = 3; # Number of keys per node - can be even
1336              
1337             my $t = Tree::Multi::new; # Construct tree
1338             $t->insert($_, $_) for 1..8;
1339              
1340             T($t, <
1341              
1342             4
1343             2 6
1344             1 3 5 7 8
1345             END
1346              
1347             local $Tree::Multi::numberOfKeysPerNode = 14; # Number of keys per node - can be even
1348              
1349             my $t = Tree::Multi::new; # Construct tree
1350             $t->insert($_, $_) for 1..15;
1351              
1352             T($t, <
1353              
1354             8
1355             1 2 3 4 5 6 7 9 10 11 12 13 14 15
1356             END
1357              
1358              
1359             =head2 Tree::Multi::Iterator::next($iter)
1360              
1361             Find the next key.
1362              
1363             Parameter Description
1364             1 $iter Iterator
1365              
1366             B
1367              
1368              
1369             local $numberOfKeysPerNode = 3; my $N = 256; my $e = 0; my $t = new;
1370              
1371             for my $n(0..$N)
1372             {$t->insert($n, $n);
1373             my @n; for(my $i = $t->iterator; $i->more; $i->next) {push @n, $i->key}
1374             ++$e unless dump(\@n) eq dump [0..$n];
1375             }
1376              
1377             is_deeply $e, 0;
1378              
1379              
1380             =head2 reverseIterator($tree)
1381              
1382             Create a reverse iterator for a tree.
1383              
1384             Parameter Description
1385             1 $tree Tree
1386              
1387             B
1388              
1389              
1390             local $numberOfKeysPerNode = 3; my $N = 64; my $e = 0;
1391              
1392             for my $n(0..$N)
1393             {my $t = new;
1394             for my $i(0..$n)
1395             {$t->insert($i, $i);
1396             }
1397             my @n;
1398              
1399             for(my $i = $t->reverseIterator; $i->less; $i->prev) # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1400              
1401             {push @n, $i->key;
1402             }
1403             ++$e unless dump(\@n) eq dump [reverse 0..$n];
1404             }
1405              
1406             is_deeply $e, 0;
1407              
1408              
1409             =head2 Tree::Multi::ReverseIterator::prev($iter)
1410              
1411             Find the previous key.
1412              
1413             Parameter Description
1414             1 $iter Iterator
1415              
1416             B
1417              
1418              
1419             local $numberOfKeysPerNode = 3; my $N = 64; my $e = 0;
1420              
1421             for my $n(0..$N)
1422             {my $t = new;
1423             for my $i(0..$n)
1424             {$t->insert($i, $i);
1425             }
1426             my @n;
1427             for(my $i = $t->reverseIterator; $i->less; $i->prev)
1428             {push @n, $i->key;
1429             }
1430             ++$e unless dump(\@n) eq dump [reverse 0..$n];
1431             }
1432              
1433             is_deeply $e, 0;
1434              
1435              
1436             =head2 flat($tree, @title)
1437              
1438             Print the keys in a tree from left right to make it easier to visualize the structure of the tree.
1439              
1440             Parameter Description
1441             1 $tree Tree
1442             2 @title Title
1443              
1444             B
1445              
1446              
1447             local $Tree::Multi::numberOfKeysPerNode = 3;
1448             my $t = new; ok $t->height == 0; ok $t->leftMost->depth == 0; ok $t->size == 0;
1449             $t->insert(1, 1); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 1;
1450             $t->insert(2, 2); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 2;
1451             $t->insert(3, 3); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 3;
1452             $t->insert(4, 4); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 4;
1453             $t->insert(5, 5); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 5;
1454             $t->insert(6, 6); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 6;
1455             $t->insert(7, 7); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 7;
1456             $t->insert(8, 8); ok $t->height == 3; ok $t->leftMost->depth == 3; ok $t->size == 8;
1457              
1458             T($t, <
1459              
1460             4
1461             2 6
1462             1 3 5 7 8
1463             END
1464              
1465              
1466              
1467             =head2 print($tree, $i)
1468              
1469             Print the keys in a tree optionally marking the active key.
1470              
1471             Parameter Description
1472             1 $tree Tree
1473             2 $i Optional index of active key
1474              
1475             B
1476              
1477              
1478             local $Tree::Multi::numberOfKeysPerNode = 4; # Number of keys per node - can be even
1479              
1480             my $t = Tree::Multi::new; # Construct tree
1481             $t->insert($_, 2 * $_) for reverse 1..32; # Load tree in reverse
1482              
1483             T($t, <
1484             17 25
1485             9 13
1486             3 5 7
1487             1 2
1488             4
1489             6
1490             8
1491             11
1492             10
1493             12
1494             15
1495             14
1496             16
1497             21
1498             19
1499             18
1500             20
1501             23
1502             22
1503             24
1504             29
1505             27
1506             26
1507             28
1508             31
1509             30
1510             32
1511             END
1512              
1513             ok $t->size == 32; # Size
1514             ok $t->height == 4; # Height
1515             ok $t->delete(16) == 2 * 16; # Delete a key
1516             ok !$t->find (16); # Key no longer present
1517             ok $t->find (17) == 34; # Find by key
1518              
1519             my @k;
1520             for(my $i = $t->iterator; $i->more; $i->next) # Iterator
1521             {push @k, $i->key unless $i->key == 17;
1522             }
1523              
1524             ok $t->delete($_) == 2 * $_ for @k; # Delete
1525              
1526             ok $t->find(17) == 34 && $t->size == 1; # Size
1527              
1528             local $Tree::Multi::numberOfKeysPerNode = 3; # Number of keys per node - can be even
1529              
1530             my $t = Tree::Multi::new; # Construct tree
1531             $t->insert($_, $_) for 1..8;
1532              
1533             T($t, <
1534              
1535             4
1536             2 6
1537             1 3 5 7 8
1538             END
1539              
1540             local $Tree::Multi::numberOfKeysPerNode = 14; # Number of keys per node - can be even
1541              
1542             my $t = Tree::Multi::new; # Construct tree
1543             $t->insert($_, $_) for 1..15;
1544              
1545             T($t, <
1546              
1547             8
1548             1 2 3 4 5 6 7 9 10 11 12 13 14 15
1549             END
1550              
1551              
1552             =head2 size($tree)
1553              
1554             Count the number of keys in a tree.
1555              
1556             Parameter Description
1557             1 $tree Tree
1558              
1559             B
1560              
1561              
1562             local $Tree::Multi::numberOfKeysPerNode = 3;
1563              
1564             my $t = new; ok $t->height == 0; ok $t->leftMost->depth == 0; ok $t->size == 0; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1565              
1566              
1567             $t->insert(1, 1); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 1; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1568              
1569              
1570             $t->insert(2, 2); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 2; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1571              
1572              
1573             $t->insert(3, 3); ok $t->height == 1; ok $t->leftMost->depth == 1; ok $t->size == 3; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1574              
1575              
1576             $t->insert(4, 4); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 4; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1577              
1578              
1579             $t->insert(5, 5); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 5; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1580              
1581              
1582             $t->insert(6, 6); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 6; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1583              
1584              
1585             $t->insert(7, 7); ok $t->height == 2; ok $t->leftMost->depth == 2; ok $t->size == 7; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1586              
1587              
1588             $t->insert(8, 8); ok $t->height == 3; ok $t->leftMost->depth == 3; ok $t->size == 8; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1589              
1590              
1591             T($t, <
1592              
1593             4
1594             2 6
1595             1 3 5 7 8
1596             END
1597              
1598              
1599              
1600              
1601             =head2 Tree::Multi Definition
1602              
1603              
1604             Iterator
1605              
1606              
1607              
1608              
1609             =head3 Output fields
1610              
1611              
1612             =head4 count
1613              
1614             Counter
1615              
1616             =head4 data
1617              
1618             Data at this position
1619              
1620             =head4 key
1621              
1622             Key at this position
1623              
1624             =head4 keys
1625              
1626             Array of key items for this node
1627              
1628             =head4 less
1629              
1630             Iteration not yet finished
1631              
1632             =head4 more
1633              
1634             Iteration not yet finished
1635              
1636             =head4 node
1637              
1638             Current node within tree
1639              
1640             =head4 pos
1641              
1642             Current position within node
1643              
1644             =head4 tree
1645              
1646             Tree we are iterating over
1647              
1648             =head4 up
1649              
1650             Parent node
1651              
1652              
1653              
1654             =head1 Private Methods
1655              
1656             =head2 new()
1657              
1658             Create a new multi-way tree node.
1659              
1660              
1661             B
1662              
1663              
1664             local $Tree::Multi::numberOfKeysPerNode = 4; # Number of keys per node - can be even
1665              
1666              
1667             my $t = Tree::Multi::new; # Construct tree # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1668              
1669             $t->insert($_, 2 * $_) for reverse 1..32; # Load tree in reverse
1670              
1671             T($t, <
1672             17 25
1673             9 13
1674             3 5 7
1675             1 2
1676             4
1677             6
1678             8
1679             11
1680             10
1681             12
1682             15
1683             14
1684             16
1685             21
1686             19
1687             18
1688             20
1689             23
1690             22
1691             24
1692             29
1693             27
1694             26
1695             28
1696             31
1697             30
1698             32
1699             END
1700              
1701             ok $t->size == 32; # Size
1702             ok $t->height == 4; # Height
1703             ok $t->delete(16) == 2 * 16; # Delete a key
1704             ok !$t->find (16); # Key no longer present
1705             ok $t->find (17) == 34; # Find by key
1706              
1707             my @k;
1708             for(my $i = $t->iterator; $i->more; $i->next) # Iterator
1709             {push @k, $i->key unless $i->key == 17;
1710             }
1711              
1712             ok $t->delete($_) == 2 * $_ for @k; # Delete
1713              
1714             ok $t->find(17) == 34 && $t->size == 1; # Size
1715              
1716             local $Tree::Multi::numberOfKeysPerNode = 3; # Number of keys per node - can be even
1717              
1718              
1719             my $t = Tree::Multi::new; # Construct tree # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1720              
1721             $t->insert($_, $_) for 1..8;
1722              
1723             T($t, <
1724              
1725             4
1726             2 6
1727             1 3 5 7 8
1728             END
1729              
1730             local $Tree::Multi::numberOfKeysPerNode = 14; # Number of keys per node - can be even
1731              
1732              
1733             my $t = Tree::Multi::new; # Construct tree # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1734              
1735             $t->insert($_, $_) for 1..15;
1736              
1737             T($t, <
1738              
1739             8
1740             1 2 3 4 5 6 7 9 10 11 12 13 14 15
1741             END
1742              
1743              
1744             =head2 minimumNumberOfKeys()
1745              
1746             Minimum number of keys per node.
1747              
1748              
1749             =head2 maximumNumberOfKeys()
1750              
1751             Maximum number of keys per node.
1752              
1753              
1754             =head2 maximumNumberOfNodes()
1755              
1756             Maximum number of children per parent.
1757              
1758              
1759             =head2 full($tree)
1760              
1761             Confirm that a node is full.
1762              
1763             Parameter Description
1764             1 $tree Tree
1765              
1766             =head2 halfFull($tree)
1767              
1768             Confirm that a node is half full.
1769              
1770             Parameter Description
1771             1 $tree Tree
1772              
1773             =head2 reUp($tree, $children)
1774              
1775             Reconnect the children to their new parent.
1776              
1777             Parameter Description
1778             1 $tree Tree
1779             2 $children Children
1780              
1781             =head2 splitFullNode($isRoot, $isLeaf, $node)
1782              
1783             Split a node if it is full.
1784              
1785             Parameter Description
1786             1 $isRoot Known to be the root if true
1787             2 $isLeaf Known to be a leaf if true
1788             3 $node Node to split
1789              
1790             =head2 findAndSplit($root, $key)
1791              
1792             Find a key in a tree splitting full nodes along the path to the key.
1793              
1794             Parameter Description
1795             1 $root Root of tree
1796             2 $key Key
1797              
1798             =head2 indexInParent($tree)
1799              
1800             Get the index of a node in its parent.
1801              
1802             Parameter Description
1803             1 $tree Tree
1804              
1805             =head2 fillFromLeftOrRight($node, $dir)
1806              
1807             Fill a node from the specified sibling.
1808              
1809             Parameter Description
1810             1 $node Node to fill
1811             2 $dir Node to fill from 0 for left or 1 for right
1812              
1813             =head2 mergeWithLeftOrRight($n, $dir)
1814              
1815             Merge two adjacent nodes.
1816              
1817             Parameter Description
1818             1 $n Node to merge into
1819             2 $dir Node to merge is on right if 1 else left
1820              
1821             =head2 merge($tree)
1822              
1823             Merge the current node with its sibling.
1824              
1825             Parameter Description
1826             1 $tree Tree
1827              
1828             =head2 mergeOrFill($tree)
1829              
1830             Make a node larger than a half node.
1831              
1832             Parameter Description
1833             1 $tree Tree
1834              
1835             =head2 deleteLeafKey($tree, $i)
1836              
1837             Delete a key in a leaf.
1838              
1839             Parameter Description
1840             1 $tree Tree
1841             2 $i Index to delete at
1842              
1843             =head2 deleteKey($tree, $i)
1844              
1845             Delete a key.
1846              
1847             Parameter Description
1848             1 $tree Tree
1849             2 $i Index to delete at
1850              
1851             =head2 T($tree, $expected, $flat)
1852              
1853             Print a tree to the log file and check it against the expected result
1854              
1855             Parameter Description
1856             1 $tree Tree
1857             2 $expected Expected print
1858             3 $flat Optionally print in flat mode if true
1859              
1860             =head2 F($tree, $expected)
1861              
1862             Print a tree flatly to the log file and check its result
1863              
1864             Parameter Description
1865             1 $tree Tree
1866             2 $expected Expected print
1867              
1868             =head2 disordered($n, $N)
1869              
1870             Disordered but stable insertions
1871              
1872             Parameter Description
1873             1 $n Keys per node
1874             2 $N Nodes
1875              
1876             =head2 disorderedCheck($t, $n, $N)
1877              
1878             Check disordered insertions
1879              
1880             Parameter Description
1881             1 $t Tree to check
1882             2 $n Keys per node
1883             3 $N Nodes
1884              
1885             =head2 randomCheck($n, $N, $T)
1886              
1887             Random insertions
1888              
1889             Parameter Description
1890             1 $n Keys per node
1891             2 $N Log 10 nodes
1892             3 $T Log 10 number of tests
1893              
1894              
1895             =head1 Index
1896              
1897              
1898             1 L - Find a key in a tree, delete it and return any associated data.
1899              
1900             2 L - Delete a key.
1901              
1902             3 L - Delete a key in a leaf.
1903              
1904             4 L - Return the depth of a node within a tree.
1905              
1906             5 L - Disordered but stable insertions
1907              
1908             6 L - Check disordered insertions
1909              
1910             7 L - Print a tree flatly to the log file and check its result
1911              
1912             8 L - Fill a node from the specified sibling.
1913              
1914             9 L - Find a key in a tree returning its associated data or undef if the key does not exist.
1915              
1916             10 L - Find a key in a tree splitting full nodes along the path to the key.
1917              
1918             11 L - Print the keys in a tree from left right to make it easier to visualize the structure of the tree.
1919              
1920             12 L - Confirm that a node is full.
1921              
1922             13 L - Confirm that a node is half full.
1923              
1924             14 L - Return the height of the tree.
1925              
1926             15 L - Get the index of a node in its parent.
1927              
1928             16 L - Insert the specified key and data into a tree.
1929              
1930             17 L - Make an iterator for a tree.
1931              
1932             18 L - Confirm that the tree is a leaf.
1933              
1934             19 L - Return the left most node below the specified one.
1935              
1936             20 L - Maximum number of keys per node.
1937              
1938             21 L - Maximum number of children per parent.
1939              
1940             22 L - Merge the current node with its sibling.
1941              
1942             23 L - Make a node larger than a half node.
1943              
1944             24 L - Merge two adjacent nodes.
1945              
1946             25 L - Minimum number of keys per node.
1947              
1948             26 L - Create a new multi-way tree node.
1949              
1950             27 L - Print the keys in a tree optionally marking the active key.
1951              
1952             28 L - Random insertions
1953              
1954             29 L - Reconnect the children to their new parent.
1955              
1956             30 L - Create a reverse iterator for a tree.
1957              
1958             31 L - Return the right most node below the specified one.
1959              
1960             32 L - Return the root node of a tree.
1961              
1962             33 L - Count the number of keys in a tree.
1963              
1964             34 L - Split a node if it is full.
1965              
1966             35 L - Print a tree to the log file and check it against the expected result
1967              
1968             36 L - Find the next key.
1969              
1970             37 L - Find the previous key.
1971              
1972             =head1 Installation
1973              
1974             This module is written in 100% Pure Perl and, thus, it is easy to read,
1975             comprehend, use, modify and install via B:
1976              
1977             sudo cpan install Tree::Multi
1978              
1979             =head1 Author
1980              
1981             L
1982              
1983             L
1984              
1985             =head1 Copyright
1986              
1987             Copyright (c) 2016-2021 Philip R Brenan.
1988              
1989             This module is free software. It may be used, redistributed and/or modified
1990             under the same terms as Perl itself.
1991              
1992             =cut
1993              
1994              
1995              
1996             # Tests and documentation
1997              
1998             sub test
1999 1     1 0 9 {my $p = __PACKAGE__;
2000 1         10 binmode($_, ":utf8") for *STDOUT, *STDERR;
2001 1 50       72 return if eval "eof(${p}::DATA)";
2002 1         56 my $s = eval "join('', <${p}::DATA>)";
2003 1 50       10 $@ and die $@;
2004 1 50   1 1 7 eval $s;
  1 100   1 1 2  
  1 50   0 1 8  
  1 0   8 1 708  
  1 50   2 1 82724  
  1 50   2   6  
  1 50   6   74  
  0 50       0  
  0 50       0  
  8 50       27  
  8         30  
  8         51  
  8         75  
  0         0  
  0         0  
  0         0  
  0         0  
  2         6  
  2         5  
  2         5  
  2         165  
  512         845  
  512         922  
  2         49  
  2         73  
  2         7  
  2         19  
  512         1206  
  512         837  
  512         932  
  2         89  
  2         16  
  2         113  
  3053         4746  
  462         10274  
  462         10574  
  462         1168  
  462         1202  
  462         10473  
  2         126  
  2         23  
  6         21  
  6         17  
  6         12  
  6         29  
  2220         140896  
  240000         457898  
  2220         29648  
  2220         254715  
  2220         55891  
  240000         5252151  
  240000         5323751  
  240000         575408  
  240000         598818  
  6         897  
2005 1 50       501 $@ and die $@;
2006 1         133 1
2007             }
2008              
2009             test unless caller;
2010              
2011             1;
2012             # podDocumentation
2013             __DATA__