/
BinarySearchTree.rakumod
116 lines (98 loc) · 2.85 KB
/
BinarySearchTree.rakumod
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
unit role BinarySearchTree[::T];
my role BinaryNode[::T] {
has T $.item is rw;
has BinaryNode $.left is rw;
has BinaryNode $.right is rw;
}
has BinaryNode $!root;
=comment PUBLIC METHODS
#| Find smallest item in the BST.
method find-min( BinarySearchTree:D: ) {
self!rec-find-min($!root).item
}
#| Find largest item in the BST.
method find-max( BinarySearchTree:D: ) {
self!iter-find-max($!root).item
}
#| Check if BST contains item $x.
method contains( BinarySearchTree:D: T $x --> Bool ) {
self!rec-contains($x, $!root)
}
#| Check if BST is empty.
method is-empty( BinarySearchTree:D: --> Bool ) {
!$!root.defined
}
#| Insert item $x into the BST.
method insert( BinarySearchTree:D: T $x --> Nil ) {
#die "Please implement the Real method
self!rec-insert($x, $!root)
}
#| Remove item $x from the BST.
method remove( BinarySearchTree:D: T $x --> Nil ) {
self!rec-remove($x, $!root)
}
=comment PRIVATE METHODS
method !rec-find-min( BinaryNode $node --> BinaryNode ) {
return BinaryNode if not $node.defined;
# current node's left subtree doesn't exist
return $node if not $node.left.defined;
# go deeper to the left
return self!rec-find-min($node.left)
}
method !iter-find-max( BinaryNode $node is copy --> BinaryNode ) {
if $node.defined {
# keep going right while current node's right subtree is defined
$node = $node.right while $node.right.defined;
}
return $node;
}
method !rec-contains( T $x, BinaryNode $node is rw --> Bool ) {
return False unless $node.defined;
if $x < $node.item {
self!rec-contains($x, $node.left)
}
elsif $node.item < $x {
self!rec-contains($x, $node.right)
}
else {
return True
}
}
method !rec-insert( T $x, BinaryNode $node is rw --> Nil ) {
if !$node.defined {
$node = BinaryNode[$(T)].new(item => $x);
}
elsif $x < $node.item {
self!rec-insert($x, $node.left)
}
elsif $node.item < $x {
self!rec-insert($x, $node.right)
}
else {
# Duplicate; do nothing
}
}
method !rec-remove( T $x, BinaryNode $node is rw --> Nil ) {
return unless $node.defined;
# go left
if $x < $node.item {
self!rec-remove($x, $node.left)
}
# go right
elsif $node.item < $x {
self!rec-remove($x, $node.right)
}
# node with two children
elsif $node.left.defined and $node.right.defined {
# find current node's right subtree's smallest data.
my $item = self!rec-find-min($node.right).item;
# replace current node's data with smallest data.
$node.item = $item;
# remove node with smallest data from right subtree.
self!rec-remove($item, $node.right);
}
# node with less than two single children
else {
$node = $node.left.defined ?? $node.left !! $node.right;
}
}