Skip to content

Commit b655b84

Browse files
committed
Complete illustrations for deletion.
1 parent 2f7ca91 commit b655b84

File tree

1 file changed

+165
-80
lines changed

1 file changed

+165
-80
lines changed

Diff for: lib/trees/avl_tree.dart

+165-80
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
5757
void add(V value) {
5858
if (isEmpty) {
5959
root = AvlNode();
60-
root = _add(root!, value, true);
60+
root = _add(root!, value);
6161
} else {
62-
root = _add(root!, value, false);
62+
root = _add(root!, value);
6363
}
6464
}
6565

@@ -152,37 +152,33 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
152152
return node;
153153
}
154154

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) {
157157
// Base case, node's value is set.
158158
node.value = value;
159159
_isTaller = true;
160160
} else if (node.value!.compareTo(value) > 0) {
161161
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.
167164
node.left = AvlNode();
168-
node.left = _add(node.left!, value, true);
165+
node.left = _add(node.left!, value);
169166
} else {
170167
// Otherwise traverse to left subtree.
171-
node.left = _add(node.left!, value, false);
168+
node.left = _add(node.left!, value);
172169
}
173170
if (_isTaller) {
174171
// Update balance factor of parent after addition.
175172
node = _aUpdateLeftBalanceFactor(node);
176173
}
177174
} else if (node.value!.compareTo(value) < 0) {
178175
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.
181177
node.right = AvlNode();
182-
node.right = _add(node.right!, value, true);
178+
node.right = _add(node.right!, value);
183179
} else {
184180
// Otherwise traverse to right subtree.
185-
node.right = _add(node.right!, value, false);
181+
node.right = _add(node.right!, value);
186182
}
187183
if (_isTaller) {
188184
// Update balance factor of parent after addition.
@@ -247,55 +243,122 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
247243
return node;
248244
}
249245

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.
252248
AvlNode<V> _dBalanceLeftHeavy(AvlNode<V> node) {
253249
// Left subtree of [node]
254250
var lChild = node.left;
255251

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) {
264253

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);
271266

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;
277269

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;
282274

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;
288288

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;
299362
}
300363
return node;
301364
}
@@ -324,8 +387,8 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
324387
node.balanceFactor = -1;
325388
rChild.balanceFactor = 1;
326389

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`.
329392
_isShorter = false;
330393
break;
331394

@@ -335,29 +398,29 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
335398
//
336399
// N N R
337400
// / \ /↶\ / \
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 ...
342405
//
343406
node = _rotateLeft(node);
344407

345408
node.balanceFactor = rChild.balanceFactor = 0;
346409

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`.
349412
break;
350413

351414
// [rChild] was left heavy. In this case, a single rotation will not
352415
// suffice so double rotation is performed. L is the root
353416
// node of [rChild]'s left subtree.
354417
//
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 █...... / \
361424
//
362425
case 1:
363426

@@ -411,6 +474,9 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
411474
// Right Left rotation is perfomed to balance [node].
412475
node.right = _rotateRight(rChild);
413476
node = _rotateLeft(node);
477+
478+
// Height of the subtree rooted at L (previously N) has changed, hence
479+
// [_isShorter] remains `true`.
414480
break;
415481
}
416482
return node;
@@ -421,8 +487,8 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
421487
/// After every deletion, sets [_isShorter] to `true`. During unwinding, if
422488
/// [_isShorter] is `true`, [_delete] calls either [_dUpdateLeftBalanceFactor]
423489
/// 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.
426492
///
427493
/// The process of checking [balanceFactor] stops when [_isShorter] becomes
428494
/// `false`.
@@ -549,29 +615,48 @@ class AvlTree<V extends Comparable> extends BinaryTreeADT<AvlNode<V>, V> {
549615
return node;
550616
}
551617

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
553619
/// right subtree.
554-
/// Subsequently, during unwinding, it can be made `false` inside
555-
/// [_dUpdateLeftBalanceFactor] or [_dUpdateRightBalanceFactor].
556620
AvlNode<V> _dUpdateRightBalanceFactor(AvlNode<V> node) {
557621
switch (node.balanceFactor) {
558622

559-
// node was balanced.
623+
// node was balanced before deletion, is left heavy now.
560624
case 0:
561-
// node is left heavy now.
625+
// N N
626+
// / \ ⟶ / \
627+
// ...█...█... ...█...█... h
628+
// h+1 ...█...▒... h+1 h+1 ...█.......
629+
//
562630
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`.
563635
_isShorter = false;
564636
break;
565637

566-
// node was right heavy.
638+
// node was right heavy before deletion, is balanced now.
567639
case -1:
568-
// node is balanced now.
640+
// N N
641+
// / \ ⟶ / \
642+
// h ...█...█... h ...█...█... h
643+
// .......▒... h+1 ...........
644+
//
569645
node.balanceFactor = 0;
646+
647+
// Height of the subtree rooted at N has decreased, [_isShorter] remains
648+
// `true`.
570649
break;
571650

572-
// node was left heavy.
651+
// node was left heavy before deletion, is imbalanced now, has to be
652+
// balanced.
573653
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+
//
575660
node = _dBalanceLeftHeavy(node);
576661
}
577662
return node;

0 commit comments

Comments
 (0)