@@ -57,9 +57,9 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
57
57
void add (V value) {
58
58
if (isEmpty) {
59
59
root = AvlNode ();
60
- root = _add (root! , value, true );
60
+ root = _add (root! , value);
61
61
} else {
62
- root = _add (root! , value, false );
62
+ root = _add (root! , value);
63
63
}
64
64
}
65
65
@@ -152,37 +152,33 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
152
152
return node;
153
153
}
154
154
155
- AvlNode <V > _add (AvlNode <V > node, V value, bool isNull ) {
156
- if (isNull ) {
155
+ AvlNode <V > _add (AvlNode <V > node, V value) {
156
+ if (node.value == null ) {
157
157
// Base case, node's value is set.
158
158
node.value = value;
159
159
_isTaller = true ;
160
160
} else if (node.value! .compareTo (value) > 0 ) {
161
161
if (node.left == null ) {
162
- // If left subtree is null,
163
- // create a new node and pass [isNull] as true.
164
- /*var newNode = _AvlNode(null);
165
- node.left = newNode;
166
- node.left = _add(newNode, value, true);*/
162
+ // If left subtree is null, create a new node so that the value can be
163
+ // assigned to it.
167
164
node.left = AvlNode ();
168
- node.left = _add (node.left! , value, true );
165
+ node.left = _add (node.left! , value);
169
166
} else {
170
167
// Otherwise traverse to left subtree.
171
- node.left = _add (node.left! , value, false );
168
+ node.left = _add (node.left! , value);
172
169
}
173
170
if (_isTaller) {
174
171
// Update balance factor of parent after addition.
175
172
node = _aUpdateLeftBalanceFactor (node);
176
173
}
177
174
} else if (node.value! .compareTo (value) < 0 ) {
178
175
if (node.right == null ) {
179
- // If right subtree is null,
180
- // create a new node and pass [isNull] as true.
176
+ // If right subtree is null, create a new node.
181
177
node.right = AvlNode ();
182
- node.right = _add (node.right! , value, true );
178
+ node.right = _add (node.right! , value);
183
179
} else {
184
180
// Otherwise traverse to right subtree.
185
- node.right = _add (node.right! , value, false );
181
+ node.right = _add (node.right! , value);
186
182
}
187
183
if (_isTaller) {
188
184
// Update balance factor of parent after addition.
@@ -247,55 +243,122 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
247
243
return node;
248
244
}
249
245
250
- /// Balances left heavy imbalanced [node] after deletion in it's
251
- /// right subtree.
246
+ /// Balances left heavy imbalanced [node] after deletion in it's right
247
+ /// subtree.
252
248
AvlNode <V > _dBalanceLeftHeavy (AvlNode <V > node) {
253
249
// Left subtree of [node]
254
250
var lChild = node.left;
255
251
256
- // [lChild] was balanced.
257
- if (lChild! .balanceFactor == 0 ) {
258
- node.balanceFactor = 1 ;
259
- lChild.balanceFactor = - 1 ;
260
- _isShorter = false ;
261
- // Single right rotation about [node] is performed to balance it.
262
- node = _rotateRight (node);
263
- }
252
+ switch (lChild! .balanceFactor) {
264
253
265
- // [lChild] was left heavy.
266
- else if (lChild.balanceFactor == 1 ) {
267
- node.balanceFactor = lChild.balanceFactor = 0 ;
268
- // Single right rotation about [node] is performed to balance it.
269
- node = _rotateRight (node);
270
- }
254
+ // [lChild] was balanced, single right rotation about [node] is performed
255
+ // to balance the [node].
256
+ case 0 :
257
+ //
258
+ // N N L
259
+ // / \ /↷\ / \
260
+ // ....L...█.. ⟶ ....L...█.. h ⟶ ..█...N....
261
+ // .../.\..▒.. h+1 .../.\..... h+1 ..█../.\...
262
+ // ..█...█.... ..█...█.... ....█...█.. h
263
+ // h+1 ..█...█.. h+1 h+1 ..█...█.. h+1 h+1 ..█..
264
+ //
265
+ node = _rotateRight (node);
271
266
272
- // [lChild] was right heavy.
273
- else {
274
- // Right subtree of [rChild].
275
- var rGrandChild = lChild.right;
276
- switch (rGrandChild! .balanceFactor) {
267
+ node.balanceFactor = 1 ;
268
+ lChild.balanceFactor = - 1 ;
277
269
278
- // [rGrandChild] was balanced.
279
- case 0 :
280
- node.balanceFactor = lChild.balanceFactor = 0 ;
281
- break ;
270
+ // Height of the subtree rooted at L (previously N) does not change,
271
+ // hence [_isShorter] is made `false`.
272
+ _isShorter = false ;
273
+ break ;
282
274
283
- // [rGrandChild] was left heavy.
284
- case 1 :
285
- node.balanceFactor = - 1 ;
286
- lChild.balanceFactor = 0 ;
287
- break ;
275
+ // [lChild] was left heavy, single right rotation about [node] is
276
+ // performed to balance it.
277
+ case 1 :
278
+ //
279
+ // N N L
280
+ // / \ /↷\ / \
281
+ // ..L...█.. ⟶ ..L...█.. h ⟶ ..█...N..
282
+ // ../.\..▒.. h+1 ../.\.... h+1 ..█../.\..
283
+ // ..█...█.. ..█...█.. ..█...█..
284
+ // h+1 ..█.... h h+1 ..█.... h h h
285
+ //
286
+ node = _rotateRight (node);
287
+ node.balanceFactor = lChild.balanceFactor = 0 ;
288
288
289
- // [rGrandChild] was right heavy.
290
- case - 1 :
291
- node.balanceFactor = 0 ;
292
- lChild.balanceFactor = 1 ;
293
- break ;
294
- }
295
- rGrandChild.balanceFactor = 0 ;
296
- // Left Right rotation is perfomed to balance [node].
297
- node.left = _rotateLeft (lChild);
298
- node = _rotateRight (node);
289
+ // Height of the subtree rooted at L (previously N) has changed, hence
290
+ // [_isShorter] remains `true`.
291
+ break ;
292
+
293
+ // [lChild] was right heavy. In this case, a single rotation will not
294
+ // suffice so double rotation is performed. R is the root
295
+ // node of [lChild]'s right subtree.
296
+ //
297
+ // N N
298
+ // / \ / \
299
+ // ..L...█.. ..L...█..
300
+ // ../.\..▒.. h+1 ../.\..▒.. h+1
301
+ // h ..█...█.. h ..█.. R .
302
+ // ......█ h+1 / \
303
+ //
304
+ case - 1 :
305
+
306
+ // Right subtree of [rChild].
307
+ var rGrandChild = lChild.right;
308
+
309
+ switch (rGrandChild! .balanceFactor) {
310
+
311
+ // [rGrandChild] was balanced.
312
+ case 0 :
313
+ // N N N
314
+ // / \ / \ /↷\ R
315
+ // ..L...█.. ..L...█.. h ......R...█.. h / \
316
+ // ../.\..▒.. h+1 ⟶ ../↶\..... ⟶ ...../.\.... ⟶ L N
317
+ // h ..█.. R .. h ..█.. R .. ....L...█.. h / \ / \
318
+ // ..../.\.. .../.\.. .../.\.... h..█...█.█...█..h
319
+ // h ..█...█.. h h ..█...█.. h h ..█...█.. h
320
+ //
321
+ node.balanceFactor = lChild.balanceFactor = 0 ;
322
+ break ;
323
+
324
+ // [rGrandChild] was left heavy.
325
+ case 1 :
326
+ // N N N
327
+ // / \ / \ /↷\ R
328
+ // ..L...█.. ..L...█.. h ......R...█.. h / \
329
+ // ../.\..▒.. h+1 ⟶ ../↶\..... ⟶ ...../.\.... ⟶ L N
330
+ // h ..█.. R .. h ..█.. R .. ....L...▀.. h-1 / \ / \
331
+ // ..../.\.. .../.\.. .../.\.... h..█...█ ▀ █..h
332
+ // h ..█...▀.. h-1 h ..█...▀.. h-1 h ..█...█.. h │
333
+ // h-1 ┘
334
+ //
335
+ node.balanceFactor = - 1 ;
336
+ lChild.balanceFactor = 0 ;
337
+ break ;
338
+
339
+ // [rGrandChild] was right heavy.
340
+ case - 1 :
341
+ // N N N
342
+ // / \ / \ /↷\ R
343
+ // ..L...█.. ..L...█.. h ......R...█.. h / \
344
+ // ../.\..▒.. h+1 ⟶ ../↶\..... ⟶ ...../.\.... ⟶ L N
345
+ // h ..█.. R .. h ..█.. R .. ....L...█.. h / \ / \
346
+ // ..../.\.. .../.\.. .../.\.... h..█ ▀ █...█..h
347
+ // h-1 ..▀...█.. h h-1 ..▀...█.. h h ..█...▀.. h-1 │
348
+ // h-1 ┘
349
+ //
350
+ node.balanceFactor = 0 ;
351
+ lChild.balanceFactor = 1 ;
352
+ break ;
353
+ }
354
+ rGrandChild.balanceFactor = 0 ;
355
+ // Left Right rotation is perfomed to balance [node].
356
+ node.left = _rotateLeft (lChild);
357
+ node = _rotateRight (node);
358
+
359
+ // Height of the subtree rooted at R (previously N) has changed, hence
360
+ // [_isShorter] remains `true`.
361
+ break ;
299
362
}
300
363
return node;
301
364
}
@@ -324,8 +387,8 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
324
387
node.balanceFactor = - 1 ;
325
388
rChild.balanceFactor = 1 ;
326
389
327
- // Height of the subtree rooted at N does not change, hence [_isShorter]
328
- // is made `false`.
390
+ // Height of the subtree rooted at R (previously N) does not change,
391
+ // hence [_isShorter] is made `false`.
329
392
_isShorter = false ;
330
393
break ;
331
394
@@ -335,29 +398,29 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
335
398
//
336
399
// N N R
337
400
// / \ /↶\ / \
338
- // ...█...R.... ⟶ h . ..█...R.... ⟶ ....N...█...
339
- // h+1 ...▒../.\... . ...../.\... .../.\..█.. h+1
340
- // .....█...█.. . . h █...█.. h ..█...█.....
341
- // ... h ...█.. h+1 . ........█.. h+1 ...... h ...
401
+ // ...█...R.... ⟶ h ..█...R.... ⟶ ....N...█...
402
+ // h+1 ...▒../.\... ...../.\... .../.\..█.. h+1
403
+ // .....█...█.. . h █...█.. h ..█...█.....
404
+ // ... h ...█.. h+1 ........█.. h+1 ...... h ...
342
405
//
343
406
node = _rotateLeft (node);
344
407
345
408
node.balanceFactor = rChild.balanceFactor = 0 ;
346
409
347
- // Height of the subtree rooted at N has changed, hence [_isShorter]
348
- // remains `true`.
410
+ // Height of the subtree rooted at R (previously N) has changed, hence
411
+ // [_isShorter] remains `true`.
349
412
break ;
350
413
351
414
// [rChild] was left heavy. In this case, a single rotation will not
352
415
// suffice so double rotation is performed. L is the root
353
416
// node of [rChild]'s left subtree.
354
417
//
355
- // N N
356
- // / \ / \
357
- // ... █...R.... ... █...R.. ..
358
- // h+1 ... ▒../.\... h+1 ... ▒. /.\. ..
359
- // ..... █...█.. h .. .. L ..█.. h
360
- // . h+1 █...... / \
418
+ // N N
419
+ // / \ / \
420
+ // ..█...R.. .. █...R..
421
+ // h+1 ..▒../.\.. h+1 ..▒. /.\..
422
+ // ...█...█.. h .. L ..█.. h
423
+ // h+1 █...... / \
361
424
//
362
425
case 1 :
363
426
@@ -411,6 +474,9 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
411
474
// Right Left rotation is perfomed to balance [node].
412
475
node.right = _rotateRight (rChild);
413
476
node = _rotateLeft (node);
477
+
478
+ // Height of the subtree rooted at L (previously N) has changed, hence
479
+ // [_isShorter] remains `true`.
414
480
break ;
415
481
}
416
482
return node;
@@ -421,8 +487,8 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
421
487
/// After every deletion, sets [_isShorter] to `true` . During unwinding, if
422
488
/// [_isShorter] is `true` , [_delete] calls either [_dUpdateLeftBalanceFactor]
423
489
/// or [_dUpdateRightBalanceFactor] to balance the node of the current call
424
- /// stack depending on whether the deletion was done in it 's left subtree or
425
- /// the right subtree respectively.
490
+ /// stack depending on whether the deletion was done in the [node] 's left
491
+ /// subtree or the right subtree respectively.
426
492
///
427
493
/// The process of checking [balanceFactor] stops when [_isShorter] becomes
428
494
/// `false` .
@@ -549,29 +615,48 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
549
615
return node;
550
616
}
551
617
552
- /// Updates [balanceFactor] of the [node] when deletion is done from it's
618
+ /// Updates [balanceFactor] of the [node] when deletion is done from it's
553
619
/// right subtree.
554
- /// Subsequently, during unwinding, it can be made `false` inside
555
- /// [_dUpdateLeftBalanceFactor] or [_dUpdateRightBalanceFactor] .
556
620
AvlNode <V > _dUpdateRightBalanceFactor (AvlNode <V > node) {
557
621
switch (node.balanceFactor) {
558
622
559
- // node was balanced.
623
+ // node was balanced before deletion, is left heavy now .
560
624
case 0 :
561
- // node is left heavy now.
625
+ // N N
626
+ // / \ ⟶ / \
627
+ // ...█...█... ...█...█... h
628
+ // h+1 ...█...▒... h+1 h+1 ...█.......
629
+ //
562
630
node.balanceFactor = 1 ;
631
+
632
+ // Balance factors of the ancestors of this [node] will remain
633
+ // unchanged (since height of the subtree rooted at N didn't change).
634
+ // Therefore [_isShorter] is set to `false`.
563
635
_isShorter = false ;
564
636
break ;
565
637
566
- // node was right heavy.
638
+ // node was right heavy before deletion, is balanced now .
567
639
case - 1 :
568
- // node is balanced now.
640
+ // N N
641
+ // / \ ⟶ / \
642
+ // h ...█...█... h ...█...█... h
643
+ // .......▒... h+1 ...........
644
+ //
569
645
node.balanceFactor = 0 ;
646
+
647
+ // Height of the subtree rooted at N has decreased, [_isShorter] remains
648
+ // `true`.
570
649
break ;
571
650
572
- // node was left heavy.
651
+ // node was left heavy before deletion, is imbalanced now, has to be
652
+ // balanced.
573
653
case 1 :
574
- // node is imbalanced now, has to be balanced.
654
+ // N N
655
+ // / \ / \
656
+ // ...█...█... ⟶ ...█...█... h-1
657
+ // ...█...▒... h ...█.......
658
+ // h+1 ...█....... h+1 ...█.......
659
+ //
575
660
node = _dBalanceLeftHeavy (node);
576
661
}
577
662
return node;
0 commit comments