1
1
/**
2
- * This file contains an implementation of an AVL tree. An AVL tree
3
- * is a special type of binary tree which self balances itself to keep
4
- * operations logarithmic.
2
+ * This file contains an implementation of an AVL tree. An AVL tree is a special type of binary tree
3
+ * which self balances itself to keep operations logarithmic.
5
4
*
6
5
* @author William Fiset, william.alexandre.fiset@gmail.com
7
- ** /
6
+ */
8
7
package com .williamfiset .datastructures .balancedtree ;
9
8
10
9
import com .williamfiset .datastructures .utils .TreePrinter ;
11
10
import com .williamfiset .datastructures .utils .TreePrinter .PrintableNode ;
12
11
13
- public class AVLTreeRecursive <T extends Comparable <T >> implements Iterable <T > {
12
+ public class AVLTreeRecursive <T extends Comparable <T >> implements Iterable <T > {
13
+
14
+ public class Node implements PrintableNode {
14
15
15
- public class Node implements PrintableNode {
16
-
17
16
// 'bf' is short for Balance Factor
18
17
public int bf ;
19
18
@@ -23,14 +22,14 @@ public class Node implements PrintableNode {
23
22
// The height of this node in the tree.
24
23
public int height ;
25
24
26
- // The left and the right children of this node.
25
+ // The left and the right children of this node.
27
26
public Node left , right ;
28
27
29
28
public Node (T value ) {
30
29
this .value = value ;
31
30
}
32
31
33
- @ Override
32
+ @ Override
34
33
public PrintableNode getLeft () {
35
34
return left ;
36
35
}
@@ -44,7 +43,6 @@ public PrintableNode getRight() {
44
43
public String getText () {
45
44
return value .toString ();
46
45
}
47
-
48
46
}
49
47
50
48
// The root node of the AVL tree.
@@ -54,7 +52,7 @@ public String getText() {
54
52
private int nodeCount = 0 ;
55
53
56
54
// The height of a rooted tree is the number of edges between the tree's
57
- // root and its furthest leaf. This means that a tree containing a single
55
+ // root and its furthest leaf. This means that a tree containing a single
58
56
// node has a height of 0.
59
57
public int height () {
60
58
if (root == null ) return 0 ;
@@ -78,7 +76,7 @@ public boolean contains(T value) {
78
76
79
77
// Recursive contains helper method.
80
78
private boolean contains (Node node , T value ) {
81
-
79
+
82
80
if (node == null ) return false ;
83
81
84
82
// Compare current value to the value in the node.
@@ -92,7 +90,6 @@ private boolean contains(Node node, T value) {
92
90
93
91
// Found value in tree.
94
92
return true ;
95
-
96
93
}
97
94
98
95
// Insert/add a value to the AVL tree. The value must not be null, O(log(n))
@@ -108,7 +105,7 @@ public boolean insert(T value) {
108
105
109
106
// Inserts a value inside the AVL tree.
110
107
private Node insert (Node node , T value ) {
111
-
108
+
112
109
// Base case.
113
110
if (node == null ) return new Node (value );
114
111
@@ -117,9 +114,10 @@ private Node insert(Node node, T value) {
117
114
118
115
// Insert node in left subtree.
119
116
if (cmp < 0 ) {
120
- node .left = insert (node .left , value );;
117
+ node .left = insert (node .left , value );
118
+ ;
121
119
122
- // Insert node in right subtree.
120
+ // Insert node in right subtree.
123
121
} else {
124
122
node .right = insert (node .right , value );
125
123
}
@@ -129,21 +127,19 @@ private Node insert(Node node, T value) {
129
127
130
128
// Re-balance tree.
131
129
return balance (node );
132
-
133
130
}
134
131
135
132
// Update a node's height and balance factor.
136
133
private void update (Node node ) {
137
-
138
- int leftNodeHeight = (node .left == null ) ? -1 : node .left .height ;
134
+
135
+ int leftNodeHeight = (node .left == null ) ? -1 : node .left .height ;
139
136
int rightNodeHeight = (node .right == null ) ? -1 : node .right .height ;
140
137
141
138
// Update this node's height.
142
139
node .height = 1 + Math .max (leftNodeHeight , rightNodeHeight );
143
140
144
141
// Update balance factor.
145
142
node .bf = rightNodeHeight - leftNodeHeight ;
146
-
147
143
}
148
144
149
145
// Re-balance a node if its balance factor is +2 or -2.
@@ -155,29 +151,27 @@ private Node balance(Node node) {
155
151
// Left-Left case.
156
152
if (node .left .bf <= 0 ) {
157
153
return leftLeftCase (node );
158
-
159
- // Left-Right case.
154
+
155
+ // Left-Right case.
160
156
} else {
161
157
return leftRightCase (node );
162
158
}
163
159
164
- // Right heavy subtree needs balancing.
160
+ // Right heavy subtree needs balancing.
165
161
} else if (node .bf == +2 ) {
166
162
167
163
// Right-Right case.
168
164
if (node .right .bf >= 0 ) {
169
165
return rightRightCase (node );
170
166
171
- // Right-Left case.
167
+ // Right-Left case.
172
168
} else {
173
169
return rightLeftCase (node );
174
170
}
175
-
176
171
}
177
172
178
173
// Node either has a balance factor of 0, +1 or -1 which is fine.
179
174
return node ;
180
-
181
175
}
182
176
183
177
private Node leftLeftCase (Node node ) {
@@ -232,41 +226,41 @@ public boolean remove(T elem) {
232
226
233
227
// Removes a value from the AVL tree.
234
228
private Node remove (Node node , T elem ) {
235
-
229
+
236
230
if (node == null ) return null ;
237
-
231
+
238
232
int cmp = elem .compareTo (node .value );
239
233
240
234
// Dig into left subtree, the value we're looking
241
235
// for is smaller than the current value.
242
236
if (cmp < 0 ) {
243
237
node .left = remove (node .left , elem );
244
238
245
- // Dig into right subtree, the value we're looking
246
- // for is greater than the current value.
239
+ // Dig into right subtree, the value we're looking
240
+ // for is greater than the current value.
247
241
} else if (cmp > 0 ) {
248
242
node .right = remove (node .right , elem );
249
243
250
- // Found the node we wish to remove.
244
+ // Found the node we wish to remove.
251
245
} else {
252
246
253
- // This is the case with only a right subtree or no subtree at all.
247
+ // This is the case with only a right subtree or no subtree at all.
254
248
// In this situation just swap the node we wish to remove
255
249
// with its right child.
256
250
if (node .left == null ) {
257
251
return node .right ;
258
-
259
- // This is the case with only a left subtree or
260
- // no subtree at all. In this situation just
261
- // swap the node we wish to remove with its left child.
252
+
253
+ // This is the case with only a left subtree or
254
+ // no subtree at all. In this situation just
255
+ // swap the node we wish to remove with its left child.
262
256
} else if (node .right == null ) {
263
257
return node .left ;
264
258
265
- // When removing a node from a binary tree with two links the
266
- // successor of the node being removed can either be the largest
267
- // value in the left subtree or the smallest value in the right
268
- // subtree. As a heuristic, I will remove from the subtree with
269
- // the greatest hieght in hopes that this may help with balancing.
259
+ // When removing a node from a binary tree with two links the
260
+ // successor of the node being removed can either be the largest
261
+ // value in the left subtree or the smallest value in the right
262
+ // subtree. As a heuristic, I will remove from the subtree with
263
+ // the greatest hieght in hopes that this may help with balancing.
270
264
} else {
271
265
272
266
// Choose to remove from left subtree
@@ -280,7 +274,7 @@ private Node remove(Node node, T elem) {
280
274
node .left = remove (node .left , successorValue );
281
275
282
276
} else {
283
-
277
+
284
278
// Swap the value of the successor into the node.
285
279
T successorValue = findMin (node .right );
286
280
node .value = successorValue ;
@@ -298,60 +292,60 @@ private Node remove(Node node, T elem) {
298
292
299
293
// Re-balance tree.
300
294
return balance (node );
301
-
302
295
}
303
296
304
297
// Helper method to find the leftmost node (which has the smallest value)
305
298
private T findMin (Node node ) {
306
- while (node .left != null )
307
- node = node .left ;
299
+ while (node .left != null ) node = node .left ;
308
300
return node .value ;
309
301
}
310
302
311
303
// Helper method to find the rightmost node (which has the largest value)
312
304
private T findMax (Node node ) {
313
- while (node .right != null )
314
- node = node .right ;
305
+ while (node .right != null ) node = node .right ;
315
306
return node .value ;
316
307
}
317
308
318
309
// Returns as iterator to traverse the tree in order.
319
- public java .util .Iterator <T > iterator () {
310
+ public java .util .Iterator <T > iterator () {
320
311
321
312
final int expectedNodeCount = nodeCount ;
322
313
final java .util .Stack <Node > stack = new java .util .Stack <>();
323
314
stack .push (root );
324
315
325
- return new java .util .Iterator <T > () {
316
+ return new java .util .Iterator <T >() {
326
317
Node trav = root ;
327
- @ Override
318
+
319
+ @ Override
328
320
public boolean hasNext () {
329
- if (expectedNodeCount != nodeCount ) throw new java .util .ConcurrentModificationException ();
321
+ if (expectedNodeCount != nodeCount ) throw new java .util .ConcurrentModificationException ();
330
322
return root != null && !stack .isEmpty ();
331
323
}
332
- @ Override
333
- public T next () {
334
-
324
+
325
+ @ Override
326
+ public T next () {
327
+
335
328
if (expectedNodeCount != nodeCount ) throw new java .util .ConcurrentModificationException ();
336
329
337
- while (trav != null && trav .left != null ) {
330
+ while (trav != null && trav .left != null ) {
338
331
stack .push (trav .left );
339
332
trav = trav .left ;
340
333
}
341
-
334
+
342
335
Node node = stack .pop ();
343
-
336
+
344
337
if (node .right != null ) {
345
338
stack .push (node .right );
346
339
trav = node .right ;
347
340
}
348
-
341
+
349
342
return node .value ;
350
343
}
351
- @ Override
344
+
345
+ @ Override
352
346
public void remove () {
353
347
throw new UnsupportedOperationException ();
354
- }
348
+ }
355
349
};
356
350
}
357
351
@@ -367,25 +361,8 @@ public boolean validateBSTInvarient(Node node) {
367
361
if (node == null ) return true ;
368
362
T val = node .value ;
369
363
boolean isValid = true ;
370
- if (node .left != null ) isValid = isValid && node .left .value .compareTo (val ) < 0 ;
364
+ if (node .left != null ) isValid = isValid && node .left .value .compareTo (val ) < 0 ;
371
365
if (node .right != null ) isValid = isValid && node .right .value .compareTo (val ) > 0 ;
372
366
return isValid && validateBSTInvarient (node .left ) && validateBSTInvarient (node .right );
373
367
}
374
-
375
368
}
376
-
377
-
378
-
379
-
380
-
381
-
382
-
383
-
384
-
385
-
386
-
387
-
388
-
389
-
390
-
391
-
0 commit comments