Skip to content

Commit 28a6c08

Browse files
ClémentClément
authored andcommitted
Simplifying AVLTree implementation.
1 parent bc0ffff commit 28a6c08

2 files changed

Lines changed: 61 additions & 92 deletions

File tree

source/code/projects/AVLTree/AVLTree/AVLTree.cs

Lines changed: 47 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
11
using System;
22
using System.Collections.Generic;
33

4+
/*
5+
* This implementation of AVL tree is
6+
* "from scratch", and stores the height
7+
* of a node as an attribute instead of
8+
* re-comptuing it when needed.
9+
* This class does not inherit from any
10+
* other class and is "standalone".
11+
*/
12+
413
public class AVLTree<T>
514
where T : IComparable<T>
15+
// We need T to realize IComparable
16+
// so that we can decide where to
17+
// insert node, exactly like BSTrees.
618
{
719
private class Node
820
{
921
public T Data { get; set; }
1022
public Node left;
1123
public Node right;
24+
// Height is implemented as an attribute
25+
// with a property.
1226
private int height;
1327
public int Height
1428
{
@@ -19,7 +33,7 @@ public int Height
1933
height = value;
2034
else
2135
throw new ApplicationException(
22-
"TreeNode height can't be < 0"
36+
"The height of a node cannot be less than 0."
2337
);
2438
}
2539
}
@@ -59,7 +73,7 @@ public T FindMin()
5973
{
6074
if (root == null)
6175
throw new ApplicationException(
62-
"FindMin called on empty BinSearchTree"
76+
"FindMin was called on an empty AVL tree."
6377
);
6478
else
6579
return FindMin(root);
@@ -100,36 +114,33 @@ private int UpdateHeight(Node nodeP)
100114
// a negative number if subtree is right-heavy
101115
// a positive number if subtree is left-heavy
102116
// 0 if the subtree is perfectly balanced.
103-
// The AVL tree will need to be re-balanced if the value
104-
// returned is greater than or equal to 2, or
105-
// less than or equal to -2.
106-
// Stated differently, if the value returned is
107-
// -1, 0 or 1, then no re-balancing will take place.
117+
108118
private int SubtreeBalance(Node nodeP)
109119
{
110120
UpdateHeight(nodeP.left);
111121
UpdateHeight(nodeP.right);
112-
int balance;
113-
if (nodeP == null)
114-
{
115-
balance = 0;
116-
}
117-
else if (nodeP.left == null && nodeP.right == null)
118-
{
119-
balance = 0;
120-
}
121-
else if (nodeP.left == null)
122-
{
123-
balance = -(nodeP.right.Height + 1);
124-
}
125-
else if (nodeP.right == null)
126-
{
127-
balance = nodeP.left.Height + 1;
128-
}
129-
else
130-
{
131-
balance = nodeP.left.Height - nodeP.right.Height;
132-
}
122+
// The resulting value is essentially
123+
// nodeP.left.Height - nodeP.right.Height
124+
// but we need to account for null values.
125+
int balance = 0;
126+
if (!(nodeP == null) &&
127+
!(nodeP.left == null && nodeP.right == null))
128+
{
129+
// If nodeP is null, or if nodeP has no children,
130+
// then balanceP is 0. Otherwise, we compute it:
131+
if (nodeP.left == null)
132+
{
133+
balance = -(nodeP.right.Height + 1);
134+
}
135+
else if (nodeP.right == null)
136+
{
137+
balance = nodeP.left.Height + 1;
138+
}
139+
else
140+
{
141+
balance = nodeP.left.Height - nodeP.right.Height;
142+
}
143+
}
133144
return balance;
134145
}
135146

@@ -259,7 +270,10 @@ private Node DoublerightChild(Node nodeP)
259270
return RotaterightChild(nodeP);
260271
}
261272

262-
private Node Insert(T valueP, Node nodeP)
273+
// Note that the following method could also use
274+
// SubtreeBalance to compute if the tree needs to be
275+
// re-balanced, instead of using GetHeight directly.
276+
private Node Insert(T valueP, Node nodeP)
263277
{
264278
if (nodeP == null)
265279
return new Node(valueP, null, null, 0);
@@ -316,54 +330,7 @@ private Node Insert(T valueP, Node nodeP)
316330
return nodeP;
317331
}
318332

319-
public int Depth()
320-
{
321-
int depth = 0;
322-
if (root != null)
323-
{
324-
depth = Depth(root, 0);
325-
}
326-
return depth;
327-
}
328-
329-
private int Depth(Node nodeP, int depth)
330-
{
331-
// "Unless proven otherwise",
332-
// we assume that the depth of the
333-
// node is the depth it received
334-
// as argument.
335-
int result = depth;
336-
// We assume the depth of
337-
// its right sub-tree
338-
// is 0.
339-
int depthL = 0;
340-
if (nodeP.left != null)
341-
{
342-
// If its left sub-tree is not null,
343-
// we inquire about its depth,
344-
// knowing that it will be 1 more
345-
// than the depth of the current node.
346-
depthL = Depth(nodeP.left, result + 1);
347-
}
348-
// We proceed similarly for the
349-
// left sub-tree.
350-
int depthR = 0;
351-
if (nodeP.right != null)
352-
{
353-
depthR = Depth(nodeP.right, result + 1);
354-
}
355-
// Finally, if at least one sub-tree
356-
// is not null, we take the max of their
357-
// depths to be the depth of the tree
358-
// starting with our current node.
359-
if (nodeP.left != null || nodeP.right != null)
360-
{
361-
result = Math.Max(depthL, depthR);
362-
}
363-
return result;
364-
}
365-
366-
public bool Remove(T value)
333+
public bool Remove(T value)
367334
{
368335
return Remove(value, ref root);
369336
}
@@ -428,12 +395,11 @@ private bool Remove(T value, ref Node nodeP)
428395
// The ToString method is simply here to help us debug.
429396
// It is not really pretty, but using pre-order and spaces
430397
// to make it easier to understand how the tree is
431-
// constructed. It also displays the depth of the tree
432-
// and the height of the nodes.
398+
// constructed.
433399

434400
public override string ToString()
435401
{
436-
string returned = "Depth: " + Depth() + "\n";
402+
string returned = "";
437403
if (root != null)
438404
{
439405
returned += Stringify(root, 0);
@@ -450,7 +416,7 @@ private string Stringify(Node nodeP, int depth)
450416
{
451417
returned += " ";
452418
}
453-
returned += nodeP + " (depth: " + depth + ")\n"; // Calls Node's ToString method.
419+
returned += nodeP + "\n"; // Calls Node's ToString method.
454420
if (nodeP.left != null)
455421
{
456422
returned += "L" + Stringify(nodeP.left, depth + 1);

source/code/projects/AVLTree/AVLTree/Program.cs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@ class Program
44
{
55
static void Main()
66
{
7-
Console.WriteLine("Test");
8-
AVLTree<int> test = new AVLTree<int>();
9-
for (int i = 1; i <= 100; i++)
10-
{
11-
test.Insert(i);
12-
}
13-
Console.WriteLine(test);
7+
AVLTree<int> avltree1 = new AVLTree<int>();
8+
9+
avltree1.Insert(10);
10+
avltree1.Insert(5);
11+
avltree1.Insert(4);
12+
avltree1.Insert(6);
13+
avltree1.Insert(20);
14+
Console.WriteLine(avltree1);
15+
avltree1.Insert(2);
16+
Console.WriteLine(avltree1);
17+
avltree1.Remove(5);
18+
Console.WriteLine(avltree1);
1419

15-
Console.WriteLine("Is 7 in tree: " + test.Remove(7));
16-
Console.WriteLine("Is 7 in tree: " + test.Remove(7));
17-
Console.WriteLine(test);
18-
}
20+
21+
}
1922
}

0 commit comments

Comments
 (0)