Acme-Pythonic

 view release on metacpan or  search on metacpan

t/algorithms.t  view on Meta::CPAN

    my ($tree_link, $target, $cmp) = @_
    my $node

    while $node = $$tree_link:
        no warnings
        my $relation = defined $cmp ? $cmp->($target, $node->{val}) \
                                    : $target <=> $node->{val}
        return ($tree_link, $node) if $relation == 0
        $tree_link = $relation > 0 ? \$node->{left} : \$node->{right}

    return ($tree_link, undef)

sub basic_tree_add:
    my ($tree_link, $target, $cmp) = @_
    my $found

    ($tree_link, $found) = basic_tree_find($tree_link, $target, $cmp)
    unless $found:
        $found = {left  => undef,
                  right => undef,
                  val   => $target}
        $$tree_link = $found

    return $found

sub basic_tree_del:
    my ($tree_link, $target, $cmp) = @_
    my $found

    ($tree_link, $found) = basic_tree_find($tree_link, $target, $cmp)
    return undef unless $found
    if ! defined $found->{left}:
        $$tree_link = $found->{right}
    elsif ! defined $found->{right}:
        $$tree_link = $found->{left}
    else:
        MERGE_SOMEHOW($tree_link, $found)

    return $found->{val}

sub MERGE_SOMEHOW:
    my ($tree_link, $found) = @_
    my $left_of_right = $found->{right}
    my $next_left

    $left_of_right = $next_left \
        while $next_left = $left_of_right->{left}

    $left_of_right->{left} = $found->{left}

    $$tree_link = $found->{right}


# ----------------------------------------------------------------------
#
# Now I will port the next subroutines meticulously from the listings in
# the book, respecting comments, whitespace, etc. Except in one place.
#
# ----------------------------------------------------------------------

# manhattan_intersection( @lines )
#   Find the intersection of strictly horizontal and vertical lines.
#   Requires basic_tree_add(), basic_tree_del(), and basic_tree_find(),
#   all defined in Chapter 3, Advanced Data Structures
sub manhattan_intersection:
    my @op # The coordinates are transformed here as operations.

    while @_:
        my @line = splice @_, 0, 4

        if $line[1] == $line[3]:        # Horizontal.
            push @op, [ @line, \&range_check_tree ]
        else:
            # Swap if upside down.
            @line = @line[0, 3, 2, 1] if $line[1] > $line[3]

            push @op, [ @line[0, 1, 2, 1], \&basic_tree_add ]
            push @op, [ @line[0, 3, 2, 3], \&basic_tree_del ]

    my $x_tree # The range check tree.
    # The x coordinate comparison routine.
    my $compare_x = sub { $_[0]->[0] <=> $_[1]->[0] }
    my @intersect # The intersections.

    # We don't reproduce the multi-line here because parens are not put correctly.
    foreach my $op in sort { $a->[1] <=> $b->[1] || $a->[4] == \&range_check_tree || $a->[0] <=> $b->[0] } @op:
        if $op->[4] == \&range_check_tree:
            push @intersect, $op->[4]->( \$x_tree, $op, $compare_x )
        else: # Add or delete.
            $op->[4]->( \$x_tree, $op, $compare_x )

    return @intersect


#
# The implementation of range_check_tree() in the book is buggy, I
# submitted the bug to the authors.
#

# range_check_tree( $tree_link, $horizontal, $compare )
#
#    Returns the list of tree nodes that are within the limits
#    $horizontal->[0] and $horizontal->[1]. Depends on the binary
#    trees of Chapter 3, Advanced Data Structures.
sub range_check_tree:
    my ( $tree, $horizontal, $compare ) = @_

    my @range         = ()     # The return value.
    my $node          = $$tree
    my $vertical_x    = $node->{val}
    my $horizontal_lo = [ $horizontal->[ 0 ] ]
    my $horizontal_hi = [ $horizontal->[ 2 ] ]

    return unless defined $$tree

    push @range, range_check_tree( \$node->{left}, $horizontal, $compare ) \
        if defined $node->{left}

    push @range, $vertical_x->[ 0 ], $horizontal->[ 1 ] \
         if $compare->( $horizontal_lo, $vertical_x ) <= 0 && \
            $compare->( $horizontal_hi, $vertical_x ) >= 0

    push @range, range_check_tree( \$node->{right}, $horizontal,
                                   $compare ) \
        if defined $node->{right}

    return @range

my @lines = (0, 0, 0, 1)
is_deeply [manhattan_intersection(@lines)], []

@lines = (0, 0, 1, 0)
is_deeply [manhattan_intersection(@lines)], []

@lines = (0, 0, 1, 0, 0, 1, 1, 1, 0, 2, 1, 2)
is_deeply [manhattan_intersection(@lines)], []

@lines = (0, 0, 0, 1, 1, 0, 1, 1, 2, 0, 2, 1)
is_deeply [manhattan_intersection(@lines)], []

@lines = (0, 1, 2, 1, 1, 0, 1, 2)
is_deeply [manhattan_intersection(@lines)], [1, 1]

# This is the example in the book.
@lines = ( 1, 6,  1, 3,  1, 2,  3, 2,  1, 1,  4, 1,
              2, 4,  7, 4,  3, 0,  3, 6,  4, 3,  4, 7,
              5, 7,  5, 4,  5, 2,  7, 2 )
# And this is the correct answer, check Figure 10-10, which is right.
is_deeply [manhattan_intersection(@lines)], [3, 1, 3, 2, 5, 4, 4, 4, 3, 4]



( run in 0.570 second using v1.01-cache-2.11-cpan-39bf76dae61 )