Skip to content

Commit a838d7f

Browse files
ClémentClément
authored andcommitted
Improving code for AVL trees.
1 parent 7ae23a1 commit a838d7f

9 files changed

Lines changed: 1191 additions & 853 deletions

File tree

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

Lines changed: 376 additions & 342 deletions
Large diffs are not rendered by default.

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

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,18 @@
22

33
class Program
44
{
5-
static void Main()
5+
static void Main()
6+
{
7+
Console.WriteLine("Test");
8+
AVLTree<int> test = new AVLTree<int>();
9+
for (int i = 1; i <= 100; i++)
610
{
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);
14-
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-
11+
test.Insert(i);
1912
}
13+
Console.WriteLine(test);
14+
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+
}
2019
}
Lines changed: 108 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,127 @@
11
using System;
22
using System.Collections.Generic;
33

4-
public class AVLTree<T> : BTree<T> where T : IComparable<T>
4+
public class AVLTree<T> : BSTree<T>
5+
where T : IComparable<T>
56
{
6-
7-
8-
public override void Insert(T valueP)
9-
{
10-
root = Insert(valueP, root);
11-
}
12-
13-
/*
14-
* Before
15-
* nodeTop --> A
16-
* / \
17-
* nodeLeft--> B C
18-
* / \
19-
* D E <-- nodeLeft.right
20-
*
21-
* After
22-
* B
23-
* / \
24-
* D A
25-
* / \
26-
* E C
27-
*/
28-
private Node RotateleftChild(Node nodeTop) // Aka left-left rotation
29-
{
30-
Node nodeLeft = nodeTop.left;
31-
nodeTop.left = nodeLeft.right;
32-
nodeLeft.right = nodeTop;
33-
return nodeLeft; // attached to caller as the new top of this subtree
34-
}
35-
36-
/*
37-
* Before
38-
* nodeTop --> A
39-
* / \
40-
* B C <-- nodeRight
41-
* / \
42-
* D E
43-
*
44-
* After
45-
* C
46-
* / \
47-
* A E
48-
* / \
49-
* B D
50-
*/
51-
private Node RotaterightChild(Node nodeTop) // Aka right-right rotation
7+
public override void Insert(T valueP)
8+
{
9+
root = Insert(valueP, root);
10+
}
11+
12+
private Node Insert(T valueP, Node nodeP)
13+
{
14+
if (nodeP == null)
15+
return new Node(valueP, null, null);
16+
else if (valueP.CompareTo(nodeP.Data) < 0) // valueP < nodeP.Data --> go left
5217
{
53-
Node nodeRight = nodeTop.right;
54-
nodeTop.right = nodeRight.left;
55-
nodeRight.left = nodeTop;
56-
return nodeRight; // attached to caller as the new top of this subtree
18+
nodeP.left = Insert(valueP, nodeP.left);
19+
int nodePLH =
20+
(nodeP.left == null) ? -1 : nodeP.left.Height;
21+
int nodePRH =
22+
(nodeP.right == null) ? -1 : nodeP.right.Height;
23+
24+
if (nodePLH - nodePRH == 2)
25+
{
26+
if (valueP.CompareTo(nodeP.left.Data) < 0)
27+
{
28+
nodeP = RotateleftChild(nodeP);
29+
}
30+
else
31+
{
32+
nodeP = DoubleleftChild(nodeP);
33+
}
34+
}
5735
}
58-
59-
/*
60-
* Before
61-
* nodeP --> A
62-
* / \
63-
* B C
64-
* / \ / \
65-
* D E F G
66-
*
67-
* After RotaterightChild
68-
* A
69-
* / \
70-
* E C
71-
* / / \
72-
* B F G
73-
* /
74-
* D
75-
*
76-
* After
77-
* E
78-
* / \
79-
* B A
80-
* / \
81-
* D C
82-
* / \
83-
* F G
84-
*/
85-
86-
private Node DoubleleftChild(Node nodeP)
36+
else if (valueP.CompareTo(nodeP.Data) > 0) // valueP > nodeP.Data --> go right
8737
{
88-
nodeP.left = RotaterightChild(nodeP.left);
89-
return RotateleftChild(nodeP);
38+
nodeP.right = Insert(valueP, nodeP.right);
39+
int nodePLH =
40+
(nodeP.left == null) ? -1 : nodeP.left.Height;
41+
int nodePRH =
42+
(nodeP.right == null) ? -1 : nodeP.right.Height;
43+
if (nodePRH - nodePLH == 2)
44+
{
45+
if (valueP.CompareTo(nodeP.right.Data) > 0)
46+
{
47+
nodeP = RotaterightChild(nodeP);
48+
}
49+
else
50+
{
51+
nodeP = DoublerightChild(nodeP);
52+
}
53+
}
9054
}
91-
92-
93-
private Node DoublerightChild(Node nodeP)
55+
else // valueP == nodeP.Data
9456
{
95-
nodeP.right = RotateleftChild(nodeP.right);
96-
return RotaterightChild(nodeP);
57+
throw new ApplicationException(
58+
"Tree did not insert "
59+
+ valueP
60+
+ " since an item with that value is already in the tree"
61+
);
9762
}
98-
99-
100-
private Node Insert(T valueP, Node nodeP)
63+
return nodeP;
64+
}
65+
66+
public override bool Delete(T dataP)
67+
{
68+
return Delete(dataP, ref root);
69+
}
70+
71+
private bool Delete(T value, ref Node nodeP)
72+
{
73+
bool found = false;
74+
if (nodeP != null)
10175
{
102-
if (nodeP == null)
103-
return new Node(valueP, null, null);
104-
else if (valueP.CompareTo(nodeP.Data) < 0) // valueP < nodeP.Data --> go left
76+
if (value.CompareTo(nodeP.Data) < 0) // value < nodeP.Data, check left subtree
77+
{
78+
found = Delete(value, ref nodeP.left); // similar to BST's find and remove method
79+
if (SubtreeBalance(nodeP) <= -2) // negative balance means heavy on right side
10580
{
106-
nodeP.left = Insert(valueP, nodeP.left);
107-
int nodePLH = (nodeP.left == null) ? -1 : nodeP.left.Height;
108-
int nodePRH = (nodeP.right == null) ? -1 : nodeP.right.Height;
109-
110-
if (nodePLH - nodePRH == 2)
111-
{
112-
if (valueP.CompareTo(nodeP.left.Data) < 0)
113-
{
114-
nodeP = RotateleftChild(nodeP);
115-
}
116-
117-
else
118-
{
119-
nodeP = DoubleleftChild(nodeP);
120-
}
121-
}
81+
if (SubtreeBalance(nodeP.right) <= 0) // children in straight line
82+
nodeP = RotaterightChild(nodeP); // rotate middle up to balance
83+
else
84+
nodeP = DoublerightChild(nodeP); // children in zig patter - needs double rotate to balance
12285
}
123-
else if (valueP.CompareTo(nodeP.Data) > 0) // valueP > nodeP.Data --> go right
86+
}
87+
else if (value.CompareTo(nodeP.Data) > 0) // value > nodeP.Data, check right subtree
88+
{
89+
found = Delete(value, ref nodeP.right);
90+
if (SubtreeBalance(nodeP) >= 2)
12491
{
125-
nodeP.right = Insert(valueP, nodeP.right);
126-
int nodePLH = (nodeP.left == null) ? -1 : nodeP.left.Height;
127-
int nodePRH = (nodeP.right == null) ? -1 : nodeP.right.Height;
128-
if (nodePRH - nodePLH == 2)
129-
{
130-
if (valueP.CompareTo(nodeP.right.Data) > 0)
131-
{
132-
nodeP = RotaterightChild(nodeP);
133-
}
134-
135-
else
136-
{
137-
nodeP = DoublerightChild(nodeP);
138-
}
139-
}
92+
if (SubtreeBalance(nodeP.left) >= 0)
93+
nodeP = RotateleftChild(nodeP);
94+
else
95+
nodeP = DoubleleftChild(nodeP);
14096
}
141-
else // valueP == nodeP.Data
97+
}
98+
else // The value was found!
99+
{
100+
found = true;
101+
if (nodeP.left != null && nodeP.right != null) // Two children
142102
{
143-
throw new ApplicationException("Tree did not insert " + valueP + " since an item with that value is already in the tree");
103+
nodeP.Data = FindMin(nodeP.right);
104+
Delete(nodeP.Data, ref nodeP.right);
105+
if (SubtreeBalance(nodeP) == 2) // Need to rebalance
106+
{
107+
if (SubtreeBalance(nodeP.left) >= 0)
108+
nodeP = RotateleftChild(nodeP);
109+
else
110+
nodeP = DoubleleftChild(nodeP);
111+
}
144112
}
145-
return nodeP;
146-
}
147-
148-
public override bool Delete(T dataP)
149-
{
150-
throw new NotImplementedException();
113+
else
114+
{
115+
nodeP = nodeP.left ?? nodeP.right; // replace with one or no child
116+
// This is equivalent to
117+
// if (nodeP.left == null){
118+
// nodeP = nodeP.right;
119+
// } else { nodeP = nodeP.left;}
120+
// Observe that if both are null, then nodeP simply
121+
// becomes null, as expected.
122+
}
123+
}
151124
}
152-
125+
return found;
126+
}
153127
}

0 commit comments

Comments
 (0)