1#####################################################################################
2# $Id: Nary.pm,v 1.3 2004/01/05 10:32:00 soriano Exp $
3#####################################################################################
4#
5# Tree::Nary
6#
7# Author: Frederic Soriano <frederic.soriano@alcatel.fr>
8# RCS Revision: $Revision: 1.3 $
9# Date: $Date: 2004/01/05 10:32:00 $
10#
11#####################################################################################
12#
13# This package is free software and is provided "as is" without express or
14# implied warranty.  It may be used, redistributed and/or modified under the
15# same terms as Perl itself.
16#
17#####################################################################################
18
19package Tree::Nary;
20
21require 5.003;
22require Exporter;
23
24@ISA = qw(Exporter);
25
26$VERSION = '1.3';
27
28use strict;
29use vars qw($TRUE $FALSE);
30use vars qw($TRAVERSE_LEAFS $TRAVERSE_NON_LEAFS $TRAVERSE_ALL $TRAVERSE_MASK);
31use vars qw($IN_ORDER $PRE_ORDER $POST_ORDER $LEVEL_ORDER);
32
33#
34# Constants
35#
36
37# Booleans
38*TRUE  = \1;
39*FALSE = \0;
40
41# Tree traverse flags
42*TRAVERSE_LEAFS		= \(1 << 0);					# Only leaf nodes should be visited.
43*TRAVERSE_NON_LEAFS	= \(1 << 1);					# Only non-leaf nodes should be visited.
44*TRAVERSE_ALL		= \($TRAVERSE_LEAFS | $TRAVERSE_NON_LEAFS);	# All nodes should be visited.
45*TRAVERSE_MASK		= \0x03;
46
47# Tree traverse orders
48*IN_ORDER		= \1;
49*PRE_ORDER		= \2;
50*POST_ORDER		= \3;
51*LEVEL_ORDER		= \4;
52
53#
54# Public methods
55#
56
57# Constructors, destructors
58
59# Creates a new Tree::Nary node object, containing the given data, if any.
60# Used to create the first node in a tree.
61sub new() {
62
63	my ($that, $newdata) = (shift, shift);
64	my $class = ref($that) || $that;
65	my $self = {
66		data		=> undef,
67		next		=> undef,
68		prev		=> undef,
69		parent		=> undef,
70		children	=> undef,
71	};
72
73	if(defined($newdata)) {
74		$self->{data} = $newdata;
75	}
76
77	# Transform $self into an object of class $class
78	bless $self, $class;
79
80	return($self);
81}
82
83# Frees allocated memory by removing circular references.
84sub _free() {
85
86	my ($self, $node) = (shift, shift);
87	my $parent = $self->new();
88
89	$parent = $node;
90
91	while($TRUE) {
92		if(defined($parent->{children})) {
93			$self->_free($parent->{children});
94		}
95		if(defined($parent->{next})) {
96			$parent = $parent->{next};
97		} else {
98			last;
99		}
100	}
101
102	return;
103}
104
105# Removes the node and its children from the tree.
106sub DESTROY() {
107
108	my ($self, $root) = (shift, shift);
109
110	if(!defined($root)) {
111		return;
112	}
113	if(!$self->is_root($root)) {
114		$self->unlink($root);
115	}
116
117	$self->_free($root);
118
119	return;
120}
121
122# Unlinks a node from a tree, resulting in two separate trees.
123sub unlink() {
124
125	my ($self, $node) = (shift, shift);
126
127	if(!defined($node)) {
128		return;
129	}
130
131	if(defined($node->{prev})) {
132		$node->{prev}->{next} = $node->{next};
133	} elsif(defined($node->{parent})) {
134		$node->{parent}->{children} = $node->{next};
135	}
136
137	$node->{parent} = undef;
138
139	if(defined($node->{next})) {
140		$node->{next}->{prev} = $node->{prev};
141		$node->{next} = undef;
142	}
143
144	$node->{prev} = undef;
145
146	return;
147}
148
149#
150# Miscellaneous info methods
151#
152
153# Returns TRUE if the given node is a root node.
154sub is_root() {
155
156	my ($self, $node) = (shift, shift);
157
158	return(!defined($node->{parent}) && !defined($node->{prev}) && !defined($node->{next}));
159}
160
161# Returns TRUE if the given node is a leaf node.
162sub is_leaf() {
163
164	my ($self, $node) = (shift, shift);
165
166	return(!defined($node->{children}));
167}
168
169# Returns TRUE if $node is an ancestor of $descendant.
170# This is true if node is the parent of descendant, or if node is the grandparent of descendant, etc.
171sub is_ancestor() {
172
173	my ($self, $node, $descendant) = (shift, shift, shift);
174
175	if(!defined($node)) {
176		return($FALSE);
177	}
178	if(!defined($descendant)) {
179		return($FALSE);
180	}
181
182	while(defined($descendant)) {
183		if(defined($descendant->{parent}) && ($descendant->{parent} == $node)) {
184			return($TRUE);
185		}
186
187		$descendant = $descendant->{parent};
188	}
189
190	return($FALSE);
191}
192
193# Gets the root of a tree.
194sub get_root() {
195
196	my ($self, $node) = (shift, shift);
197
198	if(!defined($node)) {
199		return(undef);
200	}
201
202	while(defined($node->{parent})) {
203		$node = $node->{parent};
204	}
205
206	return($node);
207}
208
209# Gets the depth of a node.
210sub depth() {
211
212	my ($self, $node) = (shift, shift);
213	my $depth = 0;
214
215	while(defined($node)) {
216		$depth++;
217		$node = $node->{parent};
218	}
219
220	return($depth);
221}
222
223# Reverses the order of the children of a node.
224sub reverse_children() {
225
226	my ($self, $node) = (shift, shift);
227	my $child = $self->new();
228	my $last = $self->new();
229
230	if(!defined($node)) {
231		return;
232	}
233
234	$child = $node->{children};
235
236	while(defined($child)) {
237		$last = $child;
238		$child = $last->{next};
239		$last->{next} = $last->{prev};
240		$last->{prev} = $child;
241	}
242
243	$node->{children} = $last;
244
245	return;
246}
247
248# Gets the maximum height of all branches beneath a node.
249# This is the maximum distance from the node to all leaf nodes.
250sub max_height() {
251
252	my ($self, $root) = (shift, shift);
253	my $child = $self->new();
254	my $max_height = 0;
255
256	# <Deep recursion on subroutine "Tree::Nary::max_height">
257	#   can be safely ignored.
258	local $^W = 0;
259
260	if(!defined($root)) {
261		return(0);
262	}
263
264	$child = $root->{children};
265
266	while(defined($child)) {
267
268		my $tmp_height = $self->max_height($child);
269
270		if($tmp_height > $max_height) {
271			$max_height = $tmp_height;
272		}
273
274		$child = $child->{next};
275	}
276
277	return($max_height + 1);
278}
279
280# Gets the number of children of a node.
281sub n_children() {
282
283	my ($self, $node) = (shift, shift);
284	my $n = 0;
285
286	if(!defined($node)) {
287		return(0);
288	}
289
290	$node = $node->{children};
291
292	while(defined($node)) {
293		$n++;
294		$node = $node->{next};
295	}
296
297	return($n);
298}
299
300# Gets the position of a node with respect to its siblings.
301# $child must be a child of $node.
302# The first child is numbered 0, the second 1, and so on.
303sub child_position() {
304
305	my ($self, $node, $child) = (shift, shift, shift);
306	my $n = 0;
307
308	if(!defined($node)) {
309		return(-1);
310	}
311	if(!defined($child)) {
312		return(-1);
313	}
314	if(defined($child->{parent}) && !($child->{parent} == $node)) {
315		return(-1);
316	}
317
318	$node = $node->{children};
319
320	while(defined($node)) {
321		if($node == $child) {
322			return($n);
323		}
324		$n++;
325		$node = $node->{next};
326	}
327
328	return(-1);
329}
330
331# Gets the position of the first child of a node which contains the given data.
332sub child_index() {
333
334	my ($self, $node, $data) = (shift, shift, shift);
335	my $n = 0;
336
337	if(!defined($node)) {
338		return(-1);
339	}
340
341	$node = $node->{children};
342
343	while(defined($node)) {
344		if($node->{data} eq $data) {
345			return($n);
346		}
347		$n++;
348		$node = $node->{next};
349	}
350
351	return(-1);
352}
353
354# Gets the first sibling of a node. This could possibly be the node itself.
355sub first_sibling() {
356
357	my ($self, $node) = (shift, shift);
358
359	if(!defined($node)) {
360		return(undef);
361	}
362
363	while(defined($node->{prev})) {
364		$node = $node->{prev};
365	}
366
367	return($node);
368}
369
370# Gets the next sibling of a node.
371sub next_sibling() {
372
373	my ($self, $node) = (shift, shift);
374
375	if(!defined($node)) {
376		return(undef);
377	}
378
379	return($node->{next});
380}
381
382# Gets the previous sibling of a node.
383sub prev_sibling() {
384
385	my ($self, $node) = (shift, shift);
386
387	if(!defined($node)) {
388		return(undef);
389	}
390
391	return($node->{prev});
392}
393
394# Gets the last sibling of a node. This could possibly be the node itself.
395sub last_sibling() {
396
397	my ($self, $node) = (shift, shift);
398
399	if(!defined($node)) {
400		return(undef);
401	}
402
403	while(defined($node->{next})) {
404		$node = $node->{next};
405	}
406
407	return($node);
408}
409
410sub _count_func() {
411
412	my ($self, $node, $flags, $nref) = (shift, shift, shift, shift);
413
414	# <Deep recursion on subroutine "Tree::Nary::_count_func"> warnings
415	#   can be safely ignored.
416	local $^W = 0;
417
418	if(defined($node->{children})) {
419
420		my $child = $self->new();
421
422		if($flags & $TRAVERSE_NON_LEAFS) {
423			$$nref++;
424		}
425
426		$child = $node->{children};
427
428		while(defined($child)) {
429			$self->_count_func($child, $flags, $nref);
430			$child = $child->{next};
431		}
432
433	} elsif($flags & $TRAVERSE_LEAFS) {
434		$$nref++;
435	}
436
437	return;
438}
439
440# Gets the number of nodes in a tree.
441sub n_nodes() {
442
443	my ($self, $root, $flags) = (shift, shift, shift);
444	my $n = 0;
445
446	if(!(defined($root))) {
447		return(0);
448	}
449	if(!($flags <= $TRAVERSE_MASK)) {
450		return(0);
451	}
452
453	$self->_count_func($root, $flags, \$n);
454
455	return($n);
456}
457
458# Gets the first child of a node.
459sub first_child() {
460
461	my ($self, $node) = (shift, shift);
462
463	if(!(defined($node))) {
464		return(undef);
465	}
466
467	return($node->{children});
468}
469
470# Gets the last child of a node.
471sub last_child() {
472
473	my ($self, $node) = (shift, shift);
474
475	if(!(defined($node))) {
476		return(undef);
477	}
478
479	$node = $node->{children};
480
481	if(defined($node)) {
482		while(defined($node->{next})) {
483			$node = $node->{next};
484		}
485	}
486
487	return($node);
488}
489
490# Gets a child of a node, using the given index.
491# the first child is at index 0.
492# If the index is too big, 'undef' is returned.
493sub nth_child() {
494
495	my ($self, $node, $n) = (shift, shift, shift);
496
497	if(!defined($node)) {
498		return(undef);
499	}
500
501	$node = $node->{children};
502
503	if(defined($node)) {
504		while(($n-- > 0) && defined($node)) {
505			$node = $node->{next};
506		}
507	}
508
509	return($node);
510}
511
512#
513# Insert methods
514#
515
516# Inserts a node beneath the parent at the given position.
517sub insert() {
518
519	my ($self, $parent, $position, $node) = (shift, shift, shift, shift);
520
521	if(!defined($parent)) {
522		return($node);
523	}
524	if(!defined($node)) {
525		return($node);
526	}
527	if(!$self->is_root($node)) {
528		return($node);
529	}
530
531	if($position > 0) {
532		return($self->insert_before($parent, $self->nth_child($parent, $position), $node));
533	} elsif($position == 0) {
534		return($self->prepend($parent, $node));
535	} else {
536		return($self->append($parent, $node));
537	}
538}
539
540# Inserts a node beneath the parent before the given sibling.
541sub insert_before() {
542
543	my ($self, $parent, $sibling, $node) = (shift, shift, shift, shift);
544
545	if(!defined($parent)) {
546		return($node);
547	}
548	if(!defined($node)) {
549		return($node);
550	}
551	if(!$self->is_root($node)) {
552		return($node);
553	}
554
555	if(defined($sibling)) {
556		if($sibling->{parent} != $parent) {
557			return($node);
558		}
559	}
560
561	$node->{parent} = $parent;
562
563	if(defined($sibling)) {
564		if(defined($sibling->{prev})) {
565			$node->{prev} = $sibling->{prev};
566			$node->{prev}->{next} = $node;
567			$node->{next} = $sibling;
568			$sibling->{prev} = $node;
569		} else {
570			$node->{parent}->{children} = $node;
571			$node->{next} = $sibling;
572			$sibling->{prev} = $node;
573		}
574	} else {
575		if(defined($parent->{children})) {
576			$sibling = $parent->{children};
577
578			while(defined($sibling->{next})) {
579				$sibling = $sibling->{next};
580			}
581
582			$node->{prev} = $sibling;
583			$sibling->{next} = $node;
584		} else {
585			$node->{parent}->{children} = $node;
586		}
587	}
588
589	return($node);
590}
591
592# Inserts a new node at the given position.
593sub insert_data() {
594
595	my ($self, $parent, $position, $data) = (shift, shift, shift, shift);
596
597	return($self->insert($parent, $position, $self->new($data)));
598}
599
600# Inserts a new node before the given sibling.
601sub insert_data_before() {
602
603	my ($self, $parent, $sibling, $data) = (shift, shift, shift, shift);
604
605	return($self->insert_before($parent, $sibling, $self->new($data)));
606}
607
608# Inserts a node as the last child of the given parent.
609sub append() {
610
611	my ($self, $parent, $node) = (shift, shift, shift);
612
613	return($self->insert_before($parent, undef, $node));
614}
615
616# Inserts a new node as the first child of the given parent.
617sub append_data() {
618
619	my ($self, $parent, $data) = (shift, shift, shift);
620
621	return($self->insert_before($parent, undef, $self->new($data)));
622}
623
624# Inserts a node as the first child of the given parent.
625sub prepend() {
626
627	my ($self, $parent, $node) = (shift, shift, shift);
628
629	if(!defined($parent)) {
630		return($node);
631	}
632
633	return($self->insert_before($parent, $parent->{children}, $node));
634}
635
636# Inserts a new node as the first child of the given parent.
637sub prepend_data() {
638
639	my ($self, $parent, $data) = (shift, shift, shift);
640
641	return($self->prepend($parent, $self->new($data)));
642}
643
644#
645# Search methods
646#
647
648sub _traverse_pre_order() {
649
650	my ($self, $node, $flags, $funcref, $argref) = (shift, shift, shift, shift, shift);
651
652	if(defined($node->{children})) {
653
654		my $child = $self->new();
655
656		if(($flags & $TRAVERSE_NON_LEAFS) && &$funcref($node, $argref)) {
657			return($TRUE);
658		}
659
660		$child = $node->{children};
661
662		while(defined($child)) {
663
664			my $current = $self->new();
665
666			$current = $child;
667			$child = $current->{next};
668			if($self->_traverse_pre_order($current, $flags, $funcref, $argref)) {
669				return($TRUE);
670			}
671		}
672
673	} elsif(($flags & $TRAVERSE_LEAFS) && &$funcref($node, $argref)) {
674		return($TRUE);
675	}
676
677	return($FALSE);
678}
679
680sub _depth_traverse_pre_order() {
681
682	my ($self, $node, $flags, $depth, $funcref, $argref) = (shift, shift, shift, shift, shift, shift);
683
684	if(defined($node->{children})) {
685
686		my $child = $self->new();
687
688		if(($flags & $TRAVERSE_NON_LEAFS) && &$funcref($node, $argref)) {
689			return($TRUE);
690		}
691
692		$depth--;
693		if(!$depth) {
694			return($FALSE);
695		}
696
697		$child = $node->{children};
698
699		while(defined($child)) {
700
701			my $current = $self->new();
702
703			$current = $child;
704			$child = $current->{next};
705
706			if($self->_traverse_pre_order($current, $flags, $depth, $funcref, $argref)) {
707				return($TRUE);
708			}
709		}
710
711	} elsif(($flags & $TRAVERSE_LEAFS) && &$funcref($node, $argref)) {
712		return($TRUE);
713	}
714
715	return($FALSE);
716}
717
718sub _traverse_post_order() {
719
720	my ($self, $node, $flags, $funcref, $argref) = (shift, shift, shift, shift, shift);
721
722	if(defined($node->{children})) {
723
724		my $child = $self->new();
725
726		$child = $node->{children};
727
728		while(defined($child)) {
729
730			my $current = $self->new();
731
732			$current = $child;
733			$child = $current->{next};
734
735			if($self->_traverse_post_order($current, $flags, $funcref, $argref)) {
736				return($TRUE);
737			}
738		}
739
740		if(($flags & $TRAVERSE_NON_LEAFS) && &$funcref($node, $argref)) {
741			return($TRUE);
742		}
743
744	} elsif(($flags & $TRAVERSE_LEAFS) && &$funcref($node, $argref)) {
745		return($TRUE);
746	}
747
748	return($FALSE);
749}
750
751sub _depth_traverse_post_order() {
752
753	my ($self, $node, $flags, $depth, $funcref, $argref) = (shift, shift, shift, shift, shift, shift);
754
755	if(defined($node->{children})) {
756
757		$depth--;
758		if($depth) {
759
760			my $child = $self->new();
761
762			$child = $node->{children};
763
764			while(defined($child)) {
765
766				my $current = $self->new();
767
768				$current = $child;
769				$child = $current->{next};
770
771				if($self->_depth_traverse_post_order($current, $flags, $depth, $funcref, $argref)) {
772					return($TRUE);
773				}
774			}
775		}
776		if(($flags & $TRAVERSE_NON_LEAFS) && &$funcref($node, $argref)) {
777			return($TRUE);
778		}
779
780	} elsif(($flags & $TRAVERSE_LEAFS) && &$funcref($node, $argref)) {
781		return($TRUE);
782	}
783
784	return($FALSE);
785}
786
787sub _traverse_in_order() {
788
789	my ($self, $node, $flags, $funcref, $argref) = (shift, shift, shift, shift, shift);
790
791	if(defined($node->{children})) {
792
793		my $child = $self->new();
794		my $current = $self->new();
795
796		$child = $node->{children};
797		$current = $child;
798		$child = $current->{next};
799
800		if($self->_traverse_in_order($current, $flags, $funcref, $argref)) {
801			return($TRUE);
802		}
803		if(($flags & $TRAVERSE_NON_LEAFS) && &$funcref($node, $argref)) {
804			return($TRUE);
805		}
806
807		while(defined($child)) {
808			$current = $child;
809			$child = $current->{next};
810			if($self->_traverse_in_order($current, $flags, $funcref, $argref)) {
811				return($TRUE);
812			}
813		}
814
815	} elsif(($flags & $TRAVERSE_LEAFS) && &$funcref($node, $argref)) {
816		return($TRUE);
817	}
818
819	return($FALSE);
820}
821
822sub _depth_traverse_in_order() {
823
824	my ($self, $node, $flags, $depth, $funcref, $argref) = (shift, shift, shift, shift, shift, shift);
825
826	if(defined($node->{children})) {
827
828		$depth--;
829		if($depth) {
830
831			my $child = $self->new();
832			my $current = $self->new();
833
834			$child = $node->{children};
835			$current = $child;
836			$child = $current->{next};
837
838			if($self->_depth_traverse_in_order($current, $flags, $depth, $funcref, $argref)) {
839				return($TRUE);
840			}
841			if(($flags & $TRAVERSE_NON_LEAFS) && &$funcref($node, $argref)) {
842				return($TRUE);
843			}
844
845			while(defined($child)) {
846				$current = $child;
847				$child = $current->{next};
848				if($self->_depth_traverse_in_order($current, $flags, $depth, $funcref, $argref)) {
849					return($TRUE);
850				}
851			}
852
853		} elsif(($flags & $TRAVERSE_NON_LEAFS) && &$funcref($node, $argref)) {
854			return($TRUE);
855		}
856
857	} elsif(($flags & $TRAVERSE_LEAFS) && &$funcref($node, $argref)) {
858		return($TRUE);
859	}
860
861	return($FALSE);
862}
863
864sub _traverse_children() {
865
866	my ($self, $node, $flags, $funcref, $argref) = (shift, shift, shift, shift, shift);
867	my $child = $self->new();
868
869	$child = $node->{children};
870
871	while(defined($child)) {
872
873		my $current = $self->new();
874
875		$current = $child;
876		$child = $current->{next};
877
878		if(defined($current->{children})) {
879			if(($flags & $TRAVERSE_NON_LEAFS) && &$funcref($current, $argref)) {
880				return($TRUE);
881			}
882		} elsif(($flags & $TRAVERSE_LEAFS) && &$funcref($current, $argref)) {
883			return($TRUE);
884		}
885	}
886
887	$child = $node->{children};
888
889	while(defined($child)) {
890
891		my $current = $self->new();
892
893		$current = $child;
894		$child = $current->{next};
895
896		if(defined($current->{children}) && $self->_traverse_children($current, $flags, $funcref, $argref)) {
897			return($TRUE);
898		}
899	}
900
901	return($FALSE);
902}
903
904sub _depth_traverse_children() {
905
906	my ($self, $node, $flags, $depth, $funcref, $argref) = (shift, shift, shift, shift, shift, shift);
907	my $child = $self->new();
908
909	$child = $node->{children};
910
911	while(defined($child)) {
912
913		my $current = $self->new();
914
915		$current = $child;
916		$child = $current->{next};
917
918		if(defined($current->{children})) {
919
920			if(($flags & $TRAVERSE_NON_LEAFS) && &$funcref($current, $argref)) {
921				return($TRUE);
922			}
923
924		} elsif(($flags & $TRAVERSE_LEAFS) && &$funcref($current, $argref)) {
925			return($TRUE);
926		}
927	}
928
929	$depth--;
930	if(!$depth) {
931		return($FALSE);
932	}
933
934	$child = $node->{children};
935
936	while(defined($child)) {
937
938		my $current = $self->new();
939
940		$current = $child;
941		$child = $current->{next};
942
943		if(defined($current->{children}) && $self->_depth_traverse_children($current, $flags, $depth, $funcref, $argref)) {
944			return($TRUE);
945		}
946	}
947
948	return($FALSE);
949}
950
951# Traverses a tree starting at the given root node. It calls the given function for each node visited.
952# The traversal can be halted at any point by returning TRUE from given function.
953sub traverse() {
954
955	my ($self, $root, $order, $flags, $depth, $funcref, $argref) = (shift, shift, shift, shift, shift, shift, shift);
956
957	if(!defined($root)) {
958		return;
959	}
960	if(!defined($funcref)) {
961		return;
962	}
963	if(!($order <= $LEVEL_ORDER)) {
964		return;
965	}
966	if(!($flags <= $TRAVERSE_MASK)) {
967		return;
968	}
969	if(!($depth == -1 || $depth > 0)) {
970		return;
971	}
972
973	SWITCH:	{
974
975		$order == $PRE_ORDER && do {
976
977			if($depth < 0) {
978				$self->_traverse_pre_order($root, $flags, $funcref, $argref);
979			} else {
980				$self->_depth_traverse_pre_order($root, $flags, $depth, $funcref, $argref);
981			}
982			last SWITCH;
983		};
984		$order == $POST_ORDER && do {
985
986			if($depth < 0) {
987				$self->_traverse_post_order($root, $flags, $funcref, $argref);
988			} else {
989				$self->_depth_traverse_post_order($root, $flags, $depth, $funcref, $argref);
990			}
991			last SWITCH;
992		};
993		$order == $IN_ORDER && do {
994
995			if($depth < 0) {
996				$self->_traverse_in_order($root, $flags, $funcref, $argref);
997			} else {
998				$self->_depth_traverse_in_order($root, $flags, $depth, $funcref, $argref);
999			}
1000			last SWITCH;
1001		};
1002		$order == $LEVEL_ORDER && do {
1003
1004			if(defined($root->{children})) {
1005				if(!(($flags & $TRAVERSE_NON_LEAFS) && &$funcref($root, $argref))) {
1006					if($depth < 0) {
1007						$self->_traverse_children($root, $flags, $funcref, $argref);
1008					} else {
1009						$depth--;
1010						if($depth) {
1011							$self->_depth_traverse_children($root, $flags, $depth, $funcref, $argref);
1012						}
1013					}
1014				}
1015			} elsif($flags & $TRAVERSE_LEAFS) {
1016				&$funcref($root, $argref);
1017			}
1018			last SWITCH;
1019		};
1020	} # End SWITCH
1021}
1022
1023# Finds a node in a tree.
1024sub find() {
1025
1026	my ($self, $root, $order, $flags, $data) = (shift, shift, shift, shift, shift);
1027	my @d;
1028
1029	if(!defined($root)) {
1030		return(undef);
1031	}
1032	if(!($order <= $LEVEL_ORDER)) {
1033		return(undef);
1034	}
1035	if(!($flags <= $TRAVERSE_MASK)) {
1036		return(undef);
1037	}
1038
1039	$d[0] = $data;
1040	$d[1] = undef;
1041
1042	$self->traverse(
1043		$root,
1044		$order,
1045		$flags,
1046		-1,
1047		sub {
1048			my ($node, $ref_of_array) = (shift, shift);
1049
1050			if($$ref_of_array[0] ne $node->{data}) {
1051				return($FALSE);
1052			}
1053
1054			$$ref_of_array[1] = $node;
1055
1056			return($TRUE);
1057		},
1058		\@d
1059	);
1060
1061	return($d[1]);
1062}
1063
1064# Finds the first child of a node with the given data.
1065sub find_child() {
1066
1067	my ($self, $node, $flags, $data) = (shift, shift, shift, shift);
1068
1069	if(!defined($node)) {
1070		return(undef);
1071	}
1072	if(!($flags <= $TRAVERSE_MASK)) {
1073		return(undef);
1074	}
1075
1076	$node = $node->{children};
1077
1078	while(defined($node)) {
1079
1080		if($node->{data} eq $data) {
1081			if($self->is_leaf($node)) {
1082				if($flags & $TRAVERSE_LEAFS) {
1083					return($node);
1084				}
1085			} else {
1086				if($flags & $TRAVERSE_NON_LEAFS) {
1087					return($node);
1088				}
1089			}
1090		}
1091
1092		$node = $node->{next};
1093	}
1094
1095	return(undef);
1096}
1097
1098# Calls a function for each of the children of a node.
1099# Note that it doesn't descend beneath the child nodes.
1100sub children_foreach() {
1101
1102	my ($self, $node, $flags, $funcref, $argref) = (shift, shift, shift, shift, shift);
1103
1104	if(!defined($node)) {
1105		return;
1106	}
1107	if(!($flags <= $TRAVERSE_MASK)) {
1108		return;
1109	}
1110	if(!defined($funcref)) {
1111		return;
1112	}
1113
1114	$node = $node->{children};
1115
1116	while(defined($node)) {
1117
1118		my $current = $self->new();
1119
1120		$current = $node;
1121		$node = $current->{next};
1122
1123		if($self->is_leaf($current)) {
1124			if($flags & $TRAVERSE_LEAFS) {
1125				&$funcref($current, $argref);
1126			}
1127		} else {
1128			if($flags & $TRAVERSE_NON_LEAFS) {
1129				&$funcref($current, $argref);
1130			}
1131		}
1132	}
1133
1134	return;
1135}
1136
1137#
1138# Sort methods
1139#
1140
1141#_pchild_ref is just gathering references
1142sub _pchild_ref() {
1143
1144	my ($node, $aref) = (shift, shift);
1145
1146	push @$aref, $node;
1147}
1148
1149# Sort a tree
1150sub tsort() {
1151
1152	my ($self, $node) = (shift, shift);
1153	my @back;
1154
1155	return if($self->is_leaf($node));
1156
1157	# gather all the children references and sort them
1158	# according to the data field backwards (Z Y X W ...)
1159	$self->children_foreach($node, $Tree::Nary::TRAVERSE_ALL, \&_pchild_ref, \@back);
1160	@back = sort { $b->{data} cmp $a->{data} } @back;
1161
1162	for (@back) {                # for every reference found (in backward order)
1163		$self->unlink($_);         # detach it from parent
1164		$self->prepend($node, $_); # prepend it 0> first child
1165		$self->tsort($_);          # call tsort recursively for its children
1166	}
1167}
1168
1169#
1170# Comparison methods
1171#
1172
1173# Generate a normalized tree
1174sub normalize() {
1175
1176	my ($self, $node)   = (shift, shift);
1177
1178	# Initialize result for a leaf
1179	my $result = '*';
1180
1181	if(!$self->is_leaf($node)) {
1182
1183		my @childs;
1184		my @chldMaps;
1185
1186		$self->children_foreach($node, $Tree::Nary::TRAVERSE_ALL, \&_pchild_ref, \@childs);
1187
1188		for(@childs) {
1189			push @chldMaps, $self->normalize($_);
1190		}
1191
1192		$result = '('.join('', sort @chldMaps).')';
1193	}
1194
1195	return($result);
1196}
1197
1198# Compares two trees and returns TRUE if they are identical
1199# in their structures and their contents
1200sub is_identical() {
1201
1202	my ($self, $t1, $t2) = (shift, shift, shift);
1203	my $i;
1204	my @t1childs;
1205	my @t2childs;
1206
1207	# Exit if one of them is leaf and the other isn't
1208	return($FALSE) if(($self->is_leaf($t1) && !$self->is_leaf($t2)) or
1209		(!$self->is_leaf($t1) && $self->is_leaf($t2)));
1210
1211	# Exit if they have different amount of children
1212	return($FALSE) if($self->n_children($t1) != $self->n_children($t2));
1213
1214	# => HERE BOTH ARE LEAFS OR PARENTS WITH SAME AMOUNT OF CHILDREN
1215
1216	return($FALSE) if($t1->{data} ne $t2->{data});     # exit if different content
1217	return($TRUE)  if($self->is_leaf($t1));              # if T1 is leaf, both are: hey, identical!!
1218
1219	# => HERE BOTH ARE PARENTS WITH SAME AMOUNT OF CHILDREN
1220
1221	# get the children references for $t1 and $t2
1222	$self->children_foreach($t1, $Tree::Nary::TRAVERSE_ALL, \&_pchild_ref, \@t1childs);
1223	$self->children_foreach($t2, $Tree::Nary::TRAVERSE_ALL,\&_pchild_ref, \@t2childs);
1224
1225	for $i (0 .. scalar(@t1childs)-1) {      # iterate all children by index
1226		next if($self->is_identical($t1childs[$i], $t2childs[$i]) == $TRUE);
1227		return($FALSE);
1228	}
1229
1230	return($TRUE);
1231}
1232
1233# Compare the structure of two trees by comparing their canonical shapes
1234sub has_same_struct() {
1235
1236	my ($self, $t1, $t2) = (shift, shift, shift);
1237	my $t1c = $self->normalize($t1);
1238	my $t2c = $self->normalize($t2);
1239
1240	return($TRUE) if($t1c eq $t2c);      # if the two canons are identical, structure is same
1241	return($FALSE);                      # structure is different
1242}
1243
12441;
1245
1246__END__
1247
1248=head1 NAME
1249
1250Tree::Nary - Perl implementation of N-ary search trees.
1251
1252=head1 SYNOPSIS
1253
1254  use Tree::Nary;
1255
1256  $node = new Tree::Nary;
1257  $another_node = new Tree::Nary;
1258
1259  $inserted_node = $node->insert($parent, $position, $node);
1260  $inserted_node = $node->insert_before($parent, $sibling, $node);
1261  $inserted_node = $node->append($parent, $node);
1262  $inserted_node = $node->prepend($parent, $node);
1263  $inserted_node = $node->insert_data($parent, $position, $data);
1264  $inserted_node = $node->insert_data_before($parent, $sibling, $data);
1265  $inserted_node = $node->append_data($parent, $data);
1266  $inserted_node = $node->prepend_data($parent, $data);
1267
1268  $node->reverse_children($node);
1269
1270  $node->traverse($node, $order, $flags, $maxdepth, $funcref, $argref);
1271
1272  $node->children_foreach($node, $flags, $funcref, $argref);
1273
1274  $root_node = $obj->get_root($node);
1275
1276  $found_node = $node->find($node, $order, $flags, $data);
1277  $found_child_node = $node->find_child($node, $flags, $data);
1278
1279  $index = $node->child_index($node, $data);
1280  $position = $node->child_position($node, $child);
1281
1282  $first_child_node = $node->first_child($node);
1283  $last_child_node = $node->last_child($node);
1284
1285  $nth_child_node = $node->nth_child($node, $index);
1286
1287  $first_sibling = $node->first_sibling($node);
1288  $next_sibling = $node->next_sibling($node);
1289  $prev_sibling = $node->prev_sibling($node);
1290  $last_sibling = $node->last_sibling($node);
1291
1292  $bool = $node->is_leaf($node);
1293  $bool = $node->is_root($node);
1294
1295  $cnt = $node->depth($node);
1296
1297  $cnt = $node->n_nodes($node);
1298  $cnt = $node->n_children($node);
1299
1300  $bool = $node->is_ancestor($node);
1301
1302  $cnt = $obj->max_height($node);
1303
1304  $node->tsort($node);
1305
1306  $normalized_node = $node->normalize($node);
1307
1308  $bool = $node->is_identical($node, $another_node);
1309  $bool = $node->has_same_struct($node, $another_node);
1310
1311  $node->unlink($node);
1312
1313=head1 DESCRIPTION
1314
1315The B<Tree::Nary> class implements N-ary trees (trees of data with any
1316number of branches), providing the organizational structure for a tree (collection)
1317of any number of nodes, but knowing nothing about the specific type of node used.
1318It can be used to display hierarchical database entries in an internal application (the
1319NIS netgroup file is an example of such a database). It offers the capability to select
1320nodes on the tree, and attachment points for nodes on the tree. Each attachment point
1321can support multiple child nodes.
1322
1323The data field contains the actual data of the node. The next and previous fields point
1324to the node's siblings (a sibling is another node with the same parent). The parent
1325field points to the parent of the node, or is I<undef> if the node is the root of the
1326tree. The children field points to the first child of the node. The other children are
1327accessed by using the next pointer of each child.
1328
1329This module is a translation (albeit not a direct one) from the C implementation of
1330N-ary trees, available in the B<GLIB distribution> (see SEE ALSO).
1331
1332=head1 GLOBAL VARIABLES
1333
1334=head2 BOOLEANS
1335
1336=over 4
1337
1338=item TRUE
1339
1340=item FALSE
1341
1342=head2 TRAVERSE FLAGS
1343
1344Specifies which nodes are visited during several of the tree functions, including
1345traverse() and find().
1346
1347=item TRAVERSE_LEAFS
1348
1349Specifies that only leaf nodes should be visited.
1350
1351=item TRAVERSE_NON_LEAFS
1352
1353Specifies that only non-leaf nodes should be visited.
1354
1355=item TRAVERSE_ALL
1356
1357Specifies that all nodes should be visited.
1358
1359=item TRAVERSE_MASK
1360
1361Combination of multiple traverse flags.
1362
1363=head2 ORDER FLAGS
1364
1365Specifies the type of traversal performed by traverse() and find().
1366
1367=item PRE_ORDER
1368
1369Visits a node, then its children.
1370
1371=item IN_ORDER
1372
1373Visits a node's left child first, then the node itself, then its right child.
1374This is the one to use if you want the output sorted according to the compare function.
1375
1376=item POST_ORDER
1377
1378Visits the node's children, then the node itself.
1379
1380=item LEVEL_ORDER
1381
1382Calls the function for each child of the node, then recursively visits each child.
1383
1384=head1 METHODS
1385
1386=head2 new( [DATA] )
1387
1388Creates a new Tree::Nary object. Used to create the first node in a tree.
1389Insert optional DATA into new created node.
1390
1391=head2 insert( PARENT, POSITION, NODE )
1392
1393Inserts a NODE beneath the PARENT at the given POSITION, returning
1394inserted NODE. If POSITION is -1, NODE is inserted as the last child
1395of PARENT.
1396
1397=head2 insert_before( PARENT, SIBLING, NODE )
1398
1399Inserts a NODE beneath the PARENT before the given SIBLING, returning
1400inserted NODE. If SIBLING is I<undef>, the NODE is inserted as the last child
1401of PARENT.
1402
1403=head2 append( PARENT, NODE )
1404
1405Inserts a NODE as the last child of the given PARENT, returning inserted NODE.
1406
1407=head2 prepend( PARENT, NODE )
1408
1409Inserts a NODE as the first child of the given PARENT, returning inserted NODE.
1410
1411=head2 insert_data( PARENT, POSITION, DATA )
1412
1413Inserts a B<new> node containing DATA, beneath the PARENT at the given POSITION.
1414Returns the new inserted node.
1415
1416=head2 insert_data_before( PARENT, SIBLING, DATA )
1417
1418Inserts a B<new> node containing DATA, beneath the PARENT, before the given
1419SIBLING. Returns the new inserted node.
1420
1421=head2 append_data( PARENT, DATA )
1422
1423Inserts a B<new> node containing DATA as the last child of the given PARENT.
1424Returns the new inserted node.
1425
1426=head2 prepend_data( PARENT, DATA )
1427
1428Inserts a B<new> node containing DATA as the first child of the given PARENT.
1429Returns the new inserted node.
1430
1431=head2 reverse_children( NODE )
1432
1433Reverses the order of the children of NODE.
1434It doesn't change the order of the grandchildren.
1435
1436=head2 traverse( NODE, ORDER, FLAGS, MAXDEPTH, FUNCTION, DATA )
1437
1438Traverses a tree starting at the given root NODE. It calls the given FUNCTION
1439(with optional user DATA to pass to the FUNCTION) for each node visited.
1440
1441The traversal can be halted at any point by returning TRUE from FUNCTION.
1442
1443The ORDER in which nodes are visited is one of IN_ORDER, PRE_ORDER, POST_ORDER and
1444LEVEL_ORDER.
1445
1446FLAGS specifies which types of children are to be visited, one of TRAVERSE_ALL,
1447TRAVERSE_LEAFS and TRAVERSE_NON_LEAFS.
1448
1449MAXDEPTH is the maximum depth of the traversal. Nodes below this depth will not
1450be visited. If MAXDEPTH is -1, all nodes in the tree are visited. If MAXDEPTH
1451is 1, only the root is visited. If MAXDEPTH is 2, the root and its children are
1452visited. And so on.
1453
1454=head2 children_foreach( NODE, FLAGS, FUNCTION, DATA )
1455
1456Calls a FUNCTION (with optional user DATA to pass to the FUNCTION) for each
1457of the children of a NODE. Note that it doesn't descend beneath the child nodes.
1458FLAGS specifies which types of children are to be visited, one of TRAVERSE_ALL,
1459TRAVERSE_LEAFS and TRAVERSE_NON_LEAFS.
1460
1461=head2 get_root( NODE )
1462
1463Gets the root node of a tree, starting from NODE.
1464
1465=head2 find( NODE, ORDER, FLAGS, DATA )
1466
1467Finds a NODE in a tree with the given DATA.
1468
1469The ORDER in which nodes are visited is one of IN_ORDER, PRE_ORDER, POST_ORDER and
1470LEVEL_ORDER.
1471
1472FLAGS specifies which types of children are to be searched, one of TRAVERSE_ALL,
1473TRAVERSE_LEAFS and TRAVERSE_NON_LEAFS.
1474
1475Returns the found node, or I<undef> if the DATA is not found.
1476
1477=head2 find_child( NODE, FLAGS, DATA )
1478
1479Finds the first child of a NODE with the given DATA.
1480
1481FLAGS specifies which types of children are to be searched, one of TRAVERSE_ALL,
1482TRAVERSE_LEAFS and TRAVERSE_NON_LEAFS.
1483
1484Returns the found child node, or I<undef> if the DATA is not found.
1485
1486=head2 child_index( NODE, DATA )
1487
1488Gets the position of the first child of a NODE which contains the given DATA.
1489Returns the index of the child of node which contains data, or -1 if DATA is
1490not found.
1491
1492=head2 child_position( NODE, CHILD )
1493
1494Gets the position of a NODE with respect to its siblings. CHILD must be a child
1495of NODE. The first child is numbered 0, the second 1, and so on. Returns the position
1496of CHILD with respect to its siblings.
1497
1498=head2 first_child( NODE )
1499
1500Returns the first child of a NODE. Returns I<undef> if NODE is I<undef> or has
1501no children.
1502
1503=head2 last_child( NODE )
1504
1505Returns the last child of a NODE. Returns I<undef> if NODE is I<undef> or has
1506no children.
1507
1508=head2 nth_child( NODE, INDEX )
1509
1510Gets a child of a NODE, using the given INDEX. The first child is at INDEX 0.
1511If the INDEX is too big, I<undef> is returned. Returns the child of NODE at INDEX.
1512
1513=head2 first_sibling( NODE )
1514
1515Returns the first sibling of a NODE. This could possibly be the NODE itself.
1516
1517=head2 prev_sibling( NODE )
1518
1519Returns the previous sibling of a NODE.
1520
1521=head2 next_sibling( NODE )
1522
1523Returns the next sibling of a NODE.
1524
1525=head2 last_sibling( NODE )
1526
1527Returns the last sibling of a NODE. This could possibly be the NODE itself.
1528
1529=head2 is_leaf( NODE )
1530
1531Returns TRUE if NODE is a leaf node (no children).
1532
1533=head2 is_root( NODE )
1534
1535Returns TRUE if NODE is a root node (no parent nor siblings).
1536
1537=head2 depth( NODE )
1538
1539Returns the depth of NODE. If NODE is I<undef>, the depth is 0. The root node has
1540a depth of 1. For the children of the root node, the depth is 2. And so on.
1541
1542=head2 n_nodes( NODE, FLAGS )
1543
1544Returns the number of nodes in a tree.
1545
1546FLAGS specifies which types of children are to be counted, one of TRAVERSE_ALL,
1547TRAVERSE_LEAFS and TRAVERSE_NON_LEAFS.
1548
1549=head2 n_children( NODE )
1550
1551Returns the number of children of NODE.
1552
1553=head2 is_ancestor( NODE, DESCENDANT )
1554
1555Returns TRUE if NODE is an ancestor of DESCENDANT. This is true if NODE is the
1556parent of DESCENDANT, or if NODE is the grandparent of DESCENDANT, etc.
1557
1558=head2 max_height( NODE )
1559
1560Returns the maximum height of all branches beneath NODE. This is the maximum
1561distance from NODE to all leaf nodes.
1562
1563If NODE is I<undef>, 0 is returned. If NODE has no children, 1 is returned.
1564If NODE has children, 2 is returned. And so on.
1565
1566=head2 tsort( NODE )
1567
1568Sorts all the children references of NODE according to the data field.
1569
1570=head2 normalize( NODE )
1571
1572Returns the normalized shape of NODE.
1573
1574=head2 is_identical( NODE, ANOTHER_NODE )
1575
1576Returns TRUE if NODE and ANOTHER_NODE have same structures and contents.
1577
1578=head2 has_same_struct( NODE, ANOTHER_NODE )
1579
1580Returns TRUE if the structure of NODE and ANOTHER_NODE are identical.
1581
1582=head2 unlink( NODE )
1583
1584Unlinks NODE from a tree, resulting in two separate trees.
1585The NODE to unlink becomes the root of a new tree.
1586
1587=head1 EXAMPLES
1588
1589An example for each function can be found in the test suite bundled with
1590B<Tree::Nary>.
1591
1592=head1 AUTHOR
1593
1594Frederic Soriano, <fsoriano@cpan.org>
1595
1596=head1 COPYRIGHT
1597
1598This package is free software and is provided "as is" without express or
1599implied warranty.  It may be used, redistributed and/or modified under the
1600same terms as Perl itself.
1601
1602=head1 SEE ALSO
1603
1604API from the GLIB project,
1605http://developer.gnome.org/doc/API/glib/glib-n-ary-trees.html.
1606
1607=cut
1608