Peter’s blog ✴ Week 125 ✴ 9 August 2021
THE WEEKLY CHALLENGE
Triples and trees
You are given binary tree such as below:
1
/ \
2 5
/ \ / \
3 4 6 7
/ \
8 10
/
9
Write a script to find the diameter of the given binary
tree.
The diameter of a binary tree is the length of the longest
path between any two nodes in a tree. It doesn’t have
to pass through the root.
For the tree shown above, possible diameters of 6 are: 3, 2, 1, 5, 7, 8, 9 or 4, 2, 1, 5, 7, 8, 9
My solution simply follows all possible paths from any starting node to any ending node, and finds the longest. Of course this isn't the fastest way to do it - for example the search could be confined to start and end at nodes with only one link - but it's simple using recursion and fast enough for any 'real' example.
#!/usr/bin/perl # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge use v5.26; # The Weekly Challenge - 2021-08-09 use utf8; # Week 125 - task 2 - Binary tree diameter use warnings; # Peter Campbell Smith binmode STDOUT, ':utf8'; my (%links, $max_length, $best_path); # args are [parent, child (, child)] binary_tree_diameter([[1, 2, 5], [2, 3, 4], [5, 6, 7], [7, 8, 10], [8, 9]]); binary_tree_diameter([[1, 2, 8], [2, 3, 6], [3, 4, 5], [6, 7], [8, 9], [9, 10], [7, 11], [11, 12]]); sub binary_tree_diameter { my ($tree, $t, @t, $j, $length, $path, $start); $tree = shift; # create $links[$id] = array of child and parent links %links = (); for $t (@$tree) { $links{$t->[0]} .= $t->[1] . ','; $links{$t->[1]} .= $t->[0] . ','; if (defined $t->[2]) { $links{$t->[0]} .= $t->[2] . ','; $links{$t->[2]} .= $t->[0] . ','; } } for $t (sort keys %links) { $links{$t} = substr($links{$t}, 0, -1); } # recurse over all start nodes $max_length = 0; $best_path = ''; for $start (sort keys %links) { ($length, $path) = find_path($start, qq[¦$start¦]); } # tidy up and show results $best_path =~ s|.(.*).|$1|; $best_path =~ s|¦| -> |g; print qq[\nInput: ]; $j = ''; for $t (@$tree) { print qq[$j$t->[0] -> $t->[1]]; print qq[, $t->[2]] if $t->[2]; print qq[\n]; $j = ' '; } printf(qq[Output: %s ... %s\n], ($max_length - 1), ($best_path)); } sub find_path { # inputs start point, length to there # returns length, max path my ($start, $path, @next, $this, $length, $new_path, $ok); # is this the longest path? ($start, $path) = @_; $length = () = $path =~ m|¦|g; if ($length - 1 > $max_length) { $max_length = $length - 1; $best_path = $path; } # add another link to the path - if possible @next = split(',', $links{$start}); for $this (@next) { next if $path =~ m|¦$this¦|; ($length, $new_path) = find_path($this, qq[$path$this¦]); } return ($length, $path); }
36 lines of code
Completed after the closing date and not submitted to GitHub
Input: 1 -> 2, 5 2 -> 3, 4 5 -> 6, 7 7 -> 8, 10 8 -> 9 Output: 6 ... 3 -> 2 -> 1 -> 5 -> 7 -> 8 -> 9 Input: 1 -> 2, 8 2 -> 3, 6 3 -> 4, 5 6 -> 7 8 -> 9 9 -> 10 7 -> 11 11 -> 12 Output: 8 ... 10 -> 9 -> 8 -> 1 -> 2 -> 6 -> 7 -> 11 -> 12
Any content of this website which has been created by Peter Campbell Smith is in the public domain