line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Tree::RedBlack; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
27676
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
55
|
|
4
|
1
|
|
|
1
|
|
558
|
use Tree::RedBlack::Node; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
32
|
|
5
|
1
|
|
|
1
|
|
7
|
use vars qw($VERSION); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3364
|
|
6
|
|
|
|
|
|
|
$VERSION = '0.5'; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 NAME |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
Tree::RedBlack - Perl implementation of Red/Black tree, a type of balanced tree. |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 SYNOPSIS |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
use Tree::RedBlack; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
my $t = new Tree::RedBlack; |
17
|
|
|
|
|
|
|
$t->insert(3, 'cat'); |
18
|
|
|
|
|
|
|
$t->insert(4, 'dog'); |
19
|
|
|
|
|
|
|
my $v = $t->find(4); |
20
|
|
|
|
|
|
|
my $min = $t->min; |
21
|
|
|
|
|
|
|
my $max = $t->max; |
22
|
|
|
|
|
|
|
$t->delete(3); |
23
|
|
|
|
|
|
|
$t->print; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 DESCRIPTION |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
This is a perl implementation of the Red/Black tree algorithm found in the book |
28
|
|
|
|
|
|
|
"Algorithms", by Cormen, Leiserson & Rivest (more commonly known as "CLR" or |
29
|
|
|
|
|
|
|
"The White Book"). A Red/Black tree is a binary tree which remains "balanced"- |
30
|
|
|
|
|
|
|
that is, the longest length from root to a node is at most one more than the |
31
|
|
|
|
|
|
|
shortest such length. It is fairly efficient; no operation takes more than |
32
|
|
|
|
|
|
|
O(lg(n)) time. |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
A Tree::RedBlack object supports the following methods: |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=over 4 |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=item new () |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Creates a new RedBlack tree object. |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=item root () |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
Returns the root node of the tree. Note that this will either be undef if no |
45
|
|
|
|
|
|
|
nodes have been added to the tree, or a Tree::RedBlack::Node object. See the |
46
|
|
|
|
|
|
|
L manual page for details on the Node object. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=item cmp (&) |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
Use this method to set a comparator subroutine. The tree defaults to lexical |
51
|
|
|
|
|
|
|
comparisons. This subroutine should be just like a comparator subroutine to |
52
|
|
|
|
|
|
|
sort, except that it doesn't do the $a, $b trick; the two elements to compare |
53
|
|
|
|
|
|
|
will just be the first two items on the stack. |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=item insert ($;$) |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
Adds a new node to the tree. The first argument is the key of the node, the |
58
|
|
|
|
|
|
|
second is its value. If a node with that key already exists, its value is |
59
|
|
|
|
|
|
|
replaced with the given value and the old value is returned. Otherwise, undef |
60
|
|
|
|
|
|
|
is returned. |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=item delete ($) |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
The argument should be either a node object to delete or the key of a node |
65
|
|
|
|
|
|
|
object to delete. WARNING!!! THIS STILL HAS BUGS!!! |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=item find ($) |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
Searches the tree to find the node with the given key. Returns the value of |
70
|
|
|
|
|
|
|
that node, or undef if a node with that key isn't found. Note, in particular, |
71
|
|
|
|
|
|
|
that you can't tell the difference between finding a node with value undef and |
72
|
|
|
|
|
|
|
not finding a node at all. If you want to determine if a node with a given key |
73
|
|
|
|
|
|
|
exists, use the node method, below. |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=item node ($) |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Searches the tree to find the node with the given key. Returns that node |
78
|
|
|
|
|
|
|
object if it is found, undef otherwise. The node object is a |
79
|
|
|
|
|
|
|
Tree::RedBlack::Node object. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=item min () |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Returns the node with the minimal key. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=item max () |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Returns the node with the maximal key. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=back |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=head1 AUTHOR |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
Benjamin Holzman |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head1 SEE ALSO |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
Tree::RedBlack::Node |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=cut |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub new { |
102
|
2
|
|
|
2
|
1
|
15
|
my $type = shift; |
103
|
2
|
|
|
|
|
14
|
return bless {'null' => Tree::RedBlack::Node::->new, |
104
|
|
|
|
|
|
|
'root' => undef}, $type; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
2
|
50
|
|
2
|
|
110
|
sub DESTROY { if ($_[0]->{'root'}) { $_[0]->{'root'}->DESTROY } } |
|
2
|
|
|
|
|
7
|
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub root { |
110
|
1
|
|
|
1
|
1
|
465
|
my $this = shift; |
111
|
1
|
|
|
|
|
12
|
return $this->{'root'}; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub cmp { |
115
|
1
|
|
|
1
|
1
|
7
|
my($this, $cr) = @_; |
116
|
1
|
|
|
|
|
3
|
$this->{'cmp'} = $cr; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub insert { |
120
|
8
|
|
|
8
|
1
|
17
|
my($this, $key, $value) = @_; |
121
|
8
|
|
|
|
|
12
|
my $cmp = $this->{'cmp'}; |
122
|
8
|
|
|
|
|
9
|
my $node = $this->{'root'}; |
123
|
8
|
|
|
|
|
9
|
my $parent; |
124
|
8
|
|
|
|
|
15
|
while ($node) { |
125
|
10
|
|
|
|
|
8
|
$parent = $node; |
126
|
10
|
100
|
|
|
|
33
|
if ($cmp ? $cmp->($key, $node->key) < 0 : $key lt $node->key) { |
|
|
100
|
|
|
|
|
|
127
|
3
|
|
|
|
|
8
|
$node = $node->left; |
128
|
|
|
|
|
|
|
} else { |
129
|
7
|
|
|
|
|
569
|
$node = $node->right; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
} |
132
|
8
|
100
|
|
|
|
13
|
if ($parent) { |
133
|
|
|
|
|
|
|
# Handle case of inserting node with duplicate key. |
134
|
6
|
100
|
|
|
|
17
|
if ($cmp ? $cmp->($parent->key, $key) == 0 : $parent->key eq $key) { |
|
|
100
|
|
|
|
|
|
135
|
1
|
|
|
|
|
3
|
my $val = $parent->val; |
136
|
1
|
|
|
|
|
28
|
$parent->val($value); |
137
|
1
|
|
|
|
|
3
|
return $val; |
138
|
|
|
|
|
|
|
} |
139
|
5
|
|
|
|
|
15
|
$node = $parent->new($key, $value); |
140
|
5
|
100
|
|
|
|
18
|
if ($this->{'cmp'} ? $this->{'cmp'}->($key, $parent->key) < 0 |
|
|
100
|
|
|
|
|
|
141
|
|
|
|
|
|
|
: $key lt $parent->key) { |
142
|
2
|
|
|
|
|
10
|
$parent->left($node); |
143
|
|
|
|
|
|
|
} else { |
144
|
3
|
|
|
|
|
7
|
$parent->right($node); |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} else { |
147
|
2
|
|
|
|
|
8
|
$this->{'root'} = $node = Tree::RedBlack::Node::->new($key, $value); |
148
|
|
|
|
|
|
|
} |
149
|
7
|
|
|
|
|
21
|
$node->color(1); |
150
|
7
|
|
100
|
|
|
37
|
while ($node != $this->{'root'} && $node->parent->color) { |
151
|
3
|
100
|
100
|
|
|
10
|
if (defined $node->parent->parent->left && $node->parent == $node->parent->parent->left) { |
152
|
1
|
|
|
|
|
3
|
my $uncle = $node->parent->parent->right; |
153
|
1
|
50
|
33
|
|
|
4
|
if ($uncle && $uncle->color) { |
154
|
0
|
|
|
|
|
0
|
$node->parent->color(0); |
155
|
0
|
|
|
|
|
0
|
$uncle->color(0); |
156
|
0
|
|
|
|
|
0
|
$node->parent->parent->color(1); |
157
|
0
|
|
|
|
|
0
|
$node = $node->parent->parent; |
158
|
|
|
|
|
|
|
} else { |
159
|
1
|
50
|
|
|
|
3
|
if ($node == $node->parent->right) { |
160
|
1
|
|
|
|
|
2
|
$node = $node->parent; |
161
|
1
|
|
|
|
|
2
|
$this->left_rotate($node); |
162
|
|
|
|
|
|
|
} |
163
|
1
|
|
|
|
|
4
|
$node->parent->color(0); |
164
|
1
|
|
|
|
|
3
|
$node->parent->parent->color(1); |
165
|
1
|
|
|
|
|
3
|
$this->right_rotate($node->parent->parent); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
} else { |
168
|
2
|
|
|
|
|
5
|
my $uncle = $node->parent->parent->left; |
169
|
2
|
100
|
66
|
|
|
8
|
if ($uncle && $uncle->color) { |
170
|
1
|
|
|
|
|
4
|
$node->parent->color(0); |
171
|
1
|
|
|
|
|
3
|
$uncle->color(0); |
172
|
1
|
|
|
|
|
3
|
$node->parent->parent->color(1); |
173
|
1
|
|
|
|
|
3
|
$node = $node->parent->parent; |
174
|
|
|
|
|
|
|
} else { |
175
|
1
|
50
|
33
|
|
|
3
|
if (defined $node->parent->left && $node == $node->parent->left) { |
176
|
0
|
|
|
|
|
0
|
$node = $node->parent; |
177
|
0
|
|
|
|
|
0
|
$this->right_rotate($node); |
178
|
|
|
|
|
|
|
} |
179
|
1
|
|
|
|
|
2
|
$node->parent->color(0); |
180
|
1
|
|
|
|
|
3
|
$node->parent->parent->color(1); |
181
|
1
|
|
|
|
|
4
|
$this->left_rotate($node->parent->parent); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
} |
185
|
7
|
|
|
|
|
21
|
$this->{'root'}->color(0); |
186
|
7
|
|
|
|
|
12
|
return; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
sub left_rotate { |
190
|
3
|
|
|
3
|
0
|
4
|
my($this, $node) = @_; |
191
|
3
|
|
|
|
|
8
|
my $child = $node->right; |
192
|
3
|
|
|
|
|
7
|
$node->right($child->left); |
193
|
3
|
100
|
|
|
|
8
|
if ($child->left) { |
194
|
1
|
|
|
|
|
4
|
$child->left->parent($node); |
195
|
|
|
|
|
|
|
} |
196
|
3
|
|
|
|
|
8
|
$child->parent($node->parent); |
197
|
3
|
100
|
|
|
|
8
|
if ($node->parent) { |
198
|
1
|
50
|
|
|
|
3
|
if ($node == $node->parent->left) { |
199
|
1
|
|
|
|
|
2
|
$node->parent->left($child); |
200
|
|
|
|
|
|
|
} else { |
201
|
0
|
|
|
|
|
0
|
$node->parent->right($child); |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
} else { |
204
|
2
|
|
|
|
|
4
|
$this->{'root'} = $child; |
205
|
|
|
|
|
|
|
} |
206
|
3
|
|
|
|
|
8
|
$child->left($node); |
207
|
3
|
|
|
|
|
7
|
$node->parent($child); |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub right_rotate { |
211
|
1
|
|
|
1
|
0
|
2
|
my($this, $node) = @_; |
212
|
1
|
|
|
|
|
2
|
my $child = $node->left; |
213
|
1
|
|
|
|
|
3
|
$node->left($child->right); |
214
|
1
|
50
|
|
|
|
2
|
if ($child->right) { |
215
|
0
|
|
|
|
|
0
|
$child->right->parent($node); |
216
|
|
|
|
|
|
|
} |
217
|
1
|
|
|
|
|
4
|
$child->parent($node->parent); |
218
|
1
|
50
|
|
|
|
3
|
if ($node->parent) { |
219
|
1
|
50
|
|
|
|
3
|
if ($node == $node->parent->right) { |
220
|
1
|
|
|
|
|
3
|
$node->parent->right($child); |
221
|
|
|
|
|
|
|
} else { |
222
|
0
|
|
|
|
|
0
|
$node->parent->left($child); |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
} else { |
225
|
0
|
|
|
|
|
0
|
$this->{'root'} = $child; |
226
|
|
|
|
|
|
|
} |
227
|
1
|
|
|
|
|
3
|
$child->right($node); |
228
|
1
|
|
|
|
|
4
|
$node->parent($child); |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub delete { |
232
|
1
|
|
|
1
|
1
|
2
|
my($this, $node_or_key) = @_; |
233
|
1
|
|
|
|
|
3
|
my $node; |
234
|
1
|
50
|
33
|
|
|
5
|
if (ref $node_or_key && $node_or_key->isa('Tree::RedBlack::Node')) { |
235
|
0
|
|
|
|
|
0
|
$node = $node_or_key; |
236
|
|
|
|
|
|
|
} else { |
237
|
1
|
50
|
|
|
|
4
|
$node = $this->node($node_or_key) or return; |
238
|
|
|
|
|
|
|
} |
239
|
1
|
|
|
|
|
1
|
my($successor, $successor_child); |
240
|
1
|
50
|
33
|
|
|
4
|
if (!($node->left && $node->right)) { |
241
|
1
|
|
|
|
|
1
|
$successor = $node; |
242
|
|
|
|
|
|
|
} else { |
243
|
0
|
|
|
|
|
0
|
$successor = $node->successor; |
244
|
|
|
|
|
|
|
} |
245
|
1
|
50
|
|
|
|
13
|
if ($successor->left) { |
246
|
0
|
|
|
|
|
0
|
$successor_child = $successor->left; |
247
|
|
|
|
|
|
|
} else { |
248
|
1
|
|
33
|
|
|
4
|
$successor_child = $successor->right || $this->{'null'}; |
249
|
|
|
|
|
|
|
} |
250
|
1
|
|
|
|
|
4
|
$successor_child->parent($successor->parent); |
251
|
1
|
50
|
33
|
|
|
7
|
if (!$successor_child || !$successor_child->parent) { |
|
|
50
|
|
|
|
|
|
252
|
0
|
|
|
|
|
0
|
$this->{'root'} = $successor_child; |
253
|
|
|
|
|
|
|
} elsif ($successor == $successor->parent->left) { |
254
|
1
|
|
|
|
|
4
|
$successor->parent->left($successor_child); |
255
|
|
|
|
|
|
|
} else { |
256
|
0
|
|
|
|
|
0
|
$successor->parent->right($successor_child); |
257
|
|
|
|
|
|
|
} |
258
|
1
|
50
|
|
|
|
4
|
if ($successor != $node) { |
259
|
0
|
|
|
|
|
0
|
$node->key($successor->key); |
260
|
0
|
|
|
|
|
0
|
$node->val($successor->val); |
261
|
|
|
|
|
|
|
} |
262
|
1
|
50
|
|
|
|
5
|
if (!$successor->color) { |
263
|
1
|
|
|
|
|
6
|
$this->delete_fixup($successor_child); |
264
|
|
|
|
|
|
|
} |
265
|
1
|
50
|
|
|
|
4
|
if (!$successor_child->parent) { |
266
|
0
|
|
|
|
|
0
|
$this->{'root'} = undef; |
267
|
|
|
|
|
|
|
} |
268
|
1
|
|
|
|
|
6
|
$successor; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub delete_fixup { |
272
|
1
|
|
|
1
|
0
|
3
|
my($this, $x) = @_; |
273
|
1
|
|
66
|
|
|
7
|
while ($x != $this->{'root'} && !$x->color) { |
274
|
1
|
50
|
|
|
|
4
|
if ($x == $x->parent->left) { |
275
|
1
|
|
|
|
|
4
|
my $w = $x->parent->right; |
276
|
1
|
50
|
|
|
|
4
|
if ($w->color) { |
277
|
0
|
|
|
|
|
0
|
$w->color(0); |
278
|
0
|
|
|
|
|
0
|
$x->parent->color(1); |
279
|
0
|
|
|
|
|
0
|
$this->left_rotate($x->parent); |
280
|
|
|
|
|
|
|
} |
281
|
1
|
50
|
33
|
|
|
5
|
if (!$w->left->color && !$w->right->color) { |
282
|
0
|
|
|
|
|
0
|
$w->color(1); |
283
|
0
|
|
|
|
|
0
|
$x = $x->parent; |
284
|
|
|
|
|
|
|
} else { |
285
|
1
|
50
|
|
|
|
4
|
if (!$w->right->color) { |
286
|
0
|
|
|
|
|
0
|
$w->left->color(0); |
287
|
0
|
|
|
|
|
0
|
$w->color(1); |
288
|
0
|
|
|
|
|
0
|
$this->right_rotate($w); |
289
|
0
|
|
|
|
|
0
|
$w = $x->parent->right; |
290
|
|
|
|
|
|
|
} |
291
|
1
|
|
|
|
|
5
|
$w->color($x->parent->color); |
292
|
1
|
|
|
|
|
5
|
$x->parent->color(0); |
293
|
1
|
|
|
|
|
4
|
$w->right->color(0); |
294
|
1
|
|
|
|
|
4
|
$this->left_rotate($x->parent); |
295
|
1
|
|
|
|
|
7
|
$x = $this->{'root'}; |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
} else { |
298
|
0
|
|
|
|
|
0
|
my $w = $x->parent->left; |
299
|
0
|
0
|
|
|
|
0
|
if ($w->color) { |
300
|
0
|
|
|
|
|
0
|
$w->color(0); |
301
|
0
|
|
|
|
|
0
|
$x->parent->color(1); |
302
|
0
|
|
|
|
|
0
|
$this->right_rotate($x->parent); |
303
|
|
|
|
|
|
|
} |
304
|
0
|
0
|
0
|
|
|
0
|
if (!$w->left->color && !$w->right->color) { |
305
|
0
|
|
|
|
|
0
|
$w->color(1); |
306
|
0
|
|
|
|
|
0
|
$x = $x->parent; |
307
|
|
|
|
|
|
|
} else { |
308
|
0
|
0
|
|
|
|
0
|
if (!$w->left->color) { |
309
|
0
|
|
|
|
|
0
|
$w->right->color(0); |
310
|
0
|
|
|
|
|
0
|
$w->color(1); |
311
|
0
|
|
|
|
|
0
|
$this->left_rotate($w); |
312
|
0
|
|
|
|
|
0
|
$w = $x->parent->left; |
313
|
|
|
|
|
|
|
} |
314
|
0
|
|
|
|
|
0
|
$w->color($x->parent->color); |
315
|
0
|
|
|
|
|
0
|
$x->parent->color(0); |
316
|
0
|
|
|
|
|
0
|
$w->left->color(0); |
317
|
0
|
|
|
|
|
0
|
$this->right_rotate($x->parent); |
318
|
0
|
|
|
|
|
0
|
$x = $this->{'root'}; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
} |
322
|
1
|
|
|
|
|
44
|
$x->color(0); |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub min { |
326
|
6
|
|
|
6
|
1
|
10
|
my $this = shift; |
327
|
6
|
100
|
|
|
|
15
|
if ($this->{'root'}) { |
328
|
5
|
100
|
|
|
|
19
|
if ($this->{'root'}->left) { |
329
|
4
|
|
|
|
|
17
|
return $this->{'root'}->left->min; |
330
|
|
|
|
|
|
|
} else { |
331
|
1
|
|
|
|
|
5
|
return $this->{'root'}; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
} |
334
|
1
|
|
|
|
|
5
|
return; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
sub max { |
338
|
6
|
|
|
6
|
1
|
13
|
my $this = shift; |
339
|
6
|
100
|
|
|
|
16
|
if ($this->{'root'}) { |
340
|
5
|
100
|
|
|
|
16
|
if ($this->{'root'}->right) { |
341
|
2
|
|
|
|
|
6
|
return $this->{'root'}->right->max; |
342
|
|
|
|
|
|
|
} else { |
343
|
3
|
|
|
|
|
12
|
return $this->{'root'}; |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
} |
346
|
1
|
|
|
|
|
4
|
return; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
sub find { |
350
|
6
|
|
|
6
|
1
|
12
|
my($this, $key) = @_; |
351
|
6
|
|
|
|
|
10
|
my $cmp = $this->{'cmp'}; |
352
|
6
|
|
|
|
|
10
|
my $node = $this->{'root'}; |
353
|
6
|
|
|
|
|
16
|
while ($node) { |
354
|
8
|
50
|
|
|
|
29
|
if ($cmp ? $cmp->($key, $node->key) == 0 : $key eq $node->key) { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
355
|
4
|
|
|
|
|
12
|
return $node->val; |
356
|
|
|
|
|
|
|
} elsif ($cmp ? $cmp->($key, $node->key) < 0 : $key lt $node->key) { |
357
|
1
|
|
|
|
|
4
|
$node = $node->left; |
358
|
|
|
|
|
|
|
} else { |
359
|
3
|
|
|
|
|
8
|
$node = $node->right; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
# Got to the end without finding the node. |
363
|
2
|
|
|
|
|
11
|
return; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
sub node { |
367
|
5
|
|
|
5
|
1
|
7
|
my($this, $key) = @_; |
368
|
5
|
|
|
|
|
7
|
my $cmp = $this->{'cmp'}; |
369
|
5
|
|
|
|
|
7
|
my $node = $this->{'root'}; |
370
|
5
|
|
|
|
|
13
|
while ($node) { |
371
|
10
|
100
|
|
|
|
33
|
if ($cmp ? $cmp->($key, $node->key) == 0 : $key eq $node->key) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
372
|
4
|
|
|
|
|
19
|
return $node; |
373
|
|
|
|
|
|
|
} elsif ($cmp ? $cmp->($key, $node->key) < 0 : $key lt $node->key) { |
374
|
4
|
|
|
|
|
12
|
$node = $node->left; |
375
|
|
|
|
|
|
|
} else { |
376
|
2
|
|
|
|
|
5
|
$node = $node->right; |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
# Got to the end without finding the node. |
380
|
1
|
|
|
|
|
3
|
return; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
1; |