aboutsummaryrefslogtreecommitdiff
path: root/challenge-130/athanasius/raku/BinTree.rakumod
blob: 32494825d889984f42feea399763c079124b262d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use v6d;

###############################################################################
=begin comment

Perl Weekly Challenge 130, Task #2: Binary Search Tree

=end comment
###############################################################################

#--------------------------------------#
# Copyright © 2021 PerlMonk Athanasius #
#--------------------------------------#

#==============================================================================
=begin comment

The BinTree class below is adapted from class BinaryTree used in the solution
to Task #2 of the Perl Weekly Challenge 94.

The implementation of methods is-bst() and !isBST() is adapted from:

    https://en.wikipedia.org/wiki/Binary_search_tree#Verification

=end comment
#==============================================================================

#==============================================================================
unit class BinTree;
#==============================================================================

#------------------------------------------------------------------------------
my class Node
#------------------------------------------------------------------------------
{
    has Int  $.value;
    has Node $.parent is rw;
    has Node $.left   is rw;
    has Node $.right  is rw;
}

has Node $!root;

#------------------------------------------------------------------------------
submethod BUILD( Int:D :$value )
#------------------------------------------------------------------------------
{
    $!root = Node.new( value => $value, parent => Nil,
                       left  => Nil,    right  => Nil );
}

#------------------------------------------------------------------------------
method append-node( UInt:D $depth, UInt:D $sequence, Int:D $value --> Bool:D )
#------------------------------------------------------------------------------
{
    my Node $parent = $!root;
    my UInt $m      = 2 ** $depth;
    my UInt $seq    = $sequence;
    my UInt $level  = $depth;

    while $level > 1
    {
        $m = ($m / 2).Int;

        if $seq < $m
        {
            $parent.left.defined  or return False;
            $parent = $parent.left;
        }
        else
        {
            $parent.right.defined or return False;
            $parent = $parent.right;
            $seq   -= $m;
        }

        --$level;
    }

    my Node $new-node = Node.new( value => $value, parent => $parent,
                                  left  => Nil,    right  => Nil );

    if $seq == 0
    {
        $parent.left  = $new-node;
    }
    else
    {
        $parent.right = $new-node;
    }

    return True;
}

#------------------------------------------------------------------------------
method is-bst( --> Bool:D )
#------------------------------------------------------------------------------
{
    return self!isBST( $!root, -Inf, +Inf );
}

subset Int-or-Inf where Int:D | -Inf | +Inf;

#------------------------------------------------------------------------------
method !isBST
(
    Node         $node,
    Int-or-Inf:D $min,
    Int-or-Inf:D $max
--> Bool:D
)
#------------------------------------------------------------------------------
{
    return True  if !$node.defined;
    return False if  $node.value < $min || $node.value > $max;

    return self!isBST( $node.left,  $min, $node.value - 1 ) &&
           self!isBST( $node.right, $node.value + 1, $max );
}

##############################################################################