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