Dumping trees to a terminal in a compact, readable form is an invaluable aid to developing and debugging tree-based algorithms. The following demonstrates a mechanism for doing this for array-based binary trees:
#! perl -slw
use strict;
use List::Util qw[ max ];
our $N;
use enum qw[ LEFT RIGHT ];
sub _traverse {
my( $code, $tree, $d, $w ) = @_;
ref $tree->[LEFT]
and $w = _traverse( $code, $tree->[LEFT], $d+1, $w )
or $code->( ++$w, $d, $tree->[LEFT] );
$code->( ++$w, $d,'^' );
ref $tree->[RIGHT]
and $w = _traverse( $code, $tree->[RIGHT], $d+1, $w )
or $code->( ++$w, $d, $tree->[RIGHT] );
return $w;
}
sub traverse(&$) { _traverse( @_, 0, 0 ); }
use enum qw[ WIDTH DEPTH NAME ];
sub dumpTree {
my $tree = shift;
my @g;
traverse{ push @g, [ @_ ]; } $tree;
my $width = max( map $_->[WIDTH], @g );
my $depth = max( map $_->[DEPTH], @g );
my @graph = map ' ' x $width, 0 .. $depth;
substr $graph[ $_->[DEPTH] ], $_->[WIDTH], 1, substr($_->[NAME],0,
+1) for @g;
unshift @graph, (' ' x $width) x 2;
for my $i ( reverse 0 .. $#graph ) {
substr( $graph[$i-1], $-[1], $+[1]-$-[1], '/' . ' ' x (length(
+$1)-2) . '\\' ),
substr( $graph[ $i ], $-[2], 1, ' ' )
while $graph[ $i ] =~ m[(\S\s*(\^)\s*\S)]g;
}
my $n;
for my $i ( reverse 0 .. $#graph ) {
$n = $+[1]-$-[1],
substr( $graph[ $i-1 ], $-[1]+1, $n-2, '_' x ($n-2))
while $graph[ $i ] =~ m[(/\s+\\)]g;
}
print for @graph, '';
return unless $N;
my @names = map[ split '', reverse ], grep !/\^/, map $_->[NAME],
+@g;
print for map{
join( ' ', '', map pop @$_//' ', @names )
} 0 .. max( map scalar @$_, @names );
}
my @a = qw[
alpha bravo charlie delta echo foxtrot golf hotel indigo
juliet kilo mike november oscar papa quebec romeo sierra
tango uniform victor whiskey xray yankee zulu
];
our $S //= 0;
srand $S if $S;
my $r;
$r = int( rand $#a ), splice @a, $r, 2, [ @a[ $r, $r+1 ]] while @a > 1
+;
@a = @{ $a[0] };
dumpTree( \@a );