Skip to content

Commit 8f6557a

Browse files
committed
Implement AVL Tree
1 parent b1df1c4 commit 8f6557a

File tree

4 files changed

+248
-69
lines changed

4 files changed

+248
-69
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Data structures and algorithms implementation in pure csharp
1919
- HashTable Chaining (Separate Chaining)
2020
- Tree
2121
- Binary Search Tree
22+
- AVL
2223

2324
### Sorting algorithms that have been implemented so far:
2425
- Bubble Sort

TODO.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ Here is Data Structures base on https://en.wikipedia.org/wiki/List_of_data_struc
8888
- [ ] Tree
8989
- [ ] Binary trees
9090
- [ ] AA tree
91-
- [ ] AVL tree
92-
- [ ] Binary search tree
91+
- [x] AVL tree
92+
- [x] Binary search tree
9393
- [ ] Binary tree
9494
- [ ] Cartesian tree
9595
- [ ] Conc-tree list
@@ -110,7 +110,7 @@ Here is Data Structures base on https://en.wikipedia.org/wiki/List_of_data_struc
110110
- [ ] WAVL tree
111111
- [ ] Weight-balanced tree
112112
- [ ] B-trees
113-
- [ ] B-tree
113+
- [x] B-tree
114114
- [ ] B+ tree
115115
- [ ] B*-tree
116116
- [ ] Dancing tree

src/ConsoleApp/Ds/Trees.cs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using DataStructures.AbstractDataTypes.Trees;
1+
using System.Diagnostics;
2+
using DataStructures.AbstractDataTypes.Trees;
23

34
namespace ConsoleApp.Ds;
45

@@ -32,16 +33,22 @@ private static void BinaryTreeUsage()
3233

3334
private static void AvlTreeUsage()
3435
{
35-
var tree = new AvlTree<int>();
36-
37-
tree.Root = tree.Insert(tree.Root, 10);
38-
tree.Root = tree.Insert(tree.Root, 11);
39-
tree.Root = tree.Insert(tree.Root, 12);
40-
tree.Root = tree.Insert(tree.Root, 13);
41-
tree.Root = tree.Insert(tree.Root, 14);
42-
tree.Root = tree.Insert(tree.Root, 15);
43-
Console.WriteLine("AVL Tree: ");
44-
tree.PrintTree(tree.Root);
36+
var avlTree = new AvlTree<int>();
37+
avlTree.Add(5);
38+
avlTree.Add(3);
39+
avlTree.Add(7);
40+
avlTree.Add(2);
41+
avlTree.Add(4);
42+
avlTree.Add(13);
43+
avlTree.Add(17);
44+
avlTree.TraversePreOrder();
45+
avlTree.TraverseInOrder();
46+
avlTree.TraversePostOrder();
47+
Console.WriteLine($"Is 13 Exists: {avlTree.IsExist(13)}");
48+
Console.WriteLine("Deleting 7...");
49+
avlTree.Delete(7);
50+
avlTree.TraverseInOrder();
51+
Console.WriteLine($"Is 7 Exists: {avlTree.IsExist(7)}");
4552
}
4653

4754
public static void Use()

src/DataStructures/AbstractDataTypes/Trees/AvlTree.cs

Lines changed: 226 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,101 +6,272 @@ public class Node
66
{
77
public Node? Left, Right;
88
public T Data;
9-
public int Height;
109

1110
public Node(T data)
1211
{
1312
Data = data;
14-
Height = 1;
1513
}
1614
}
1715

1816
private Node? _root;
1917

20-
private static int GetHeight(Node? node)
18+
public void Add(T data)
2119
{
22-
return node?.Height ?? 0;
23-
}
20+
var newNode = new Node(data);
21+
if (_root is null)
22+
{
23+
_root = newNode;
24+
return;
25+
}
2426

25-
private static Node RightRotate(Node y)
26-
{
27-
var x = y.Left;
28-
var t2 = x.Right;
29-
x.Right = y;
30-
y.Left = t2;
31-
y.Height = Math.Max(GetHeight(y.Left), GetHeight(y.Right)) + 1;
32-
x.Height = Math.Max(GetHeight(x.Left), GetHeight(x.Right)) + 1;
33-
return x;
27+
_root = Insert(_root, newNode);
3428
}
3529

36-
private static Node LeftRotate(Node x)
30+
private static Node Insert(Node? current, Node newNode)
3731
{
38-
Node y = x.Right;
39-
Node T2 = y.Left;
40-
y.Left = x;
41-
x.Right = T2;
42-
x.Height = Math.Max(GetHeight(x.Left), GetHeight(x.Right)) + 1;
43-
y.Height = Math.Max(GetHeight(y.Left), GetHeight(y.Right)) + 1;
44-
return y;
32+
if (current is null)
33+
{
34+
current = newNode;
35+
return current;
36+
}
37+
38+
var comparer = Comparer<T>.Default;
39+
var c = comparer.Compare(newNode.Data, current.Data);
40+
41+
switch (c)
42+
{
43+
case < 0:
44+
current.Left = Insert(current.Left, newNode);
45+
current = GetBalancedTree(current);
46+
break;
47+
case > 0:
48+
current.Right = Insert(current.Right, newNode);
49+
current = GetBalancedTree(current);
50+
break;
51+
default:
52+
return current; //Exists!
53+
}
54+
55+
return current;
4556
}
4657

47-
private static int GetBalance(Node? node)
58+
public void Delete(T target)
4859
{
49-
if (node == null)
50-
return 0;
51-
52-
return GetHeight(node.Left) - GetHeight(node.Right);
60+
_root = Delete(_root, target);
5361
}
5462

55-
public Node Insert(Node node, T key)
63+
private static Node? Delete(Node? current, T target)
5664
{
65+
if (current is null)
66+
{
67+
return null;
68+
}
69+
5770
var comparer = Comparer<T>.Default;
58-
if (node == null)
59-
return (new Node(key));
71+
var c = comparer.Compare(target, current.Data);
6072

61-
var c = comparer.Compare(key, node.Data);
6273
switch (c)
6374
{
6475
case < 0:
65-
node.Left = Insert(node.Left, key);
76+
current.Left = Delete(current.Left, target);
77+
if (GetBalanceFactor(current) == -2) //here
78+
{
79+
current = GetBalanceFactor(current.Right) <= 0 ? RotateRr(current) : RotateRl(current);
80+
}
81+
6682
break;
6783
case > 0:
68-
node.Right = Insert(node.Right, key);
84+
current.Right = Delete(current.Right, target);
85+
if (GetBalanceFactor(current) == 2)
86+
{
87+
current = GetBalanceFactor(current.Left) >= 0 ? RotateLl(current) : RotateLr(current);
88+
}
89+
90+
break;
91+
default: //Found!
92+
if (current.Right != null)
93+
{
94+
var parent = current.Right;
95+
while (parent.Left != null)
96+
{
97+
parent = parent.Left;
98+
}
99+
100+
current.Data = parent.Data;
101+
current.Right = Delete(current.Right, parent.Data);
102+
if (GetBalanceFactor(current) == 2)
103+
{
104+
current = GetBalanceFactor(current.Left) >= 0 ? RotateLl(current) : RotateLr(current);
105+
}
106+
}
107+
else
108+
{
109+
return current.Left;
110+
}
111+
69112
break;
70-
default:
71-
return node; //Exists!
72113
}
73114

74-
node.Height = 1 + Math.Max(GetHeight(node.Left), GetHeight(node.Right));
75-
int balance = GetBalance(node);
76-
if (balance > 1 && comparer.Compare(key, node.Left.Data) < 0)
77-
return RightRotate(node);
78-
if (balance < -1 && comparer.Compare(key, node.Right.Data) > 0)
79-
return LeftRotate(node);
80-
if (balance > 1 && comparer.Compare(key, node.Left.Data) > 0)
115+
return current;
116+
}
117+
118+
public bool IsExist(T key)
119+
{
120+
if (_root is null)
121+
return false;
122+
var node = Find(key, _root);
123+
if (node is null)
124+
return false;
125+
126+
var comparer = Comparer<T>.Default;
127+
return comparer.Compare(node.Data, key) == 0;
128+
}
129+
130+
private static Node? Find(T target, Node? current)
131+
{
132+
if (current is null)
133+
return null;
134+
135+
var comparer = Comparer<T>.Default;
136+
var c = comparer.Compare(target, current.Data);
137+
return c switch
81138
{
82-
node.Left = LeftRotate(node.Left);
83-
return RightRotate(node);
84-
}
139+
< 0 => Find(target, current.Left),
140+
> 0 => Find(target, current.Right),
141+
_ => current
142+
};
143+
}
85144

86-
if (balance < -1 && comparer.Compare(key, node.Right.Data) < 0)
145+
private static Node GetBalancedTree(Node current)
146+
{
147+
var bFactor = GetBalanceFactor(current);
148+
switch (bFactor)
87149
{
88-
node.Right = RightRotate(node.Right);
89-
return LeftRotate(node);
150+
case > 1 when GetBalanceFactor(current.Left) > 0:
151+
current = RotateLl(current);
152+
break;
153+
case > 1:
154+
current = RotateLr(current);
155+
break;
156+
case < -1 when GetBalanceFactor(current.Right) > 0:
157+
current = RotateRl(current);
158+
break;
159+
case < -1:
160+
current = RotateRr(current);
161+
break;
90162
}
91163

92-
return node;
164+
return current;
165+
}
166+
167+
private static Node RotateRr(Node parent)
168+
{
169+
var pivot = parent.Right;
170+
parent.Right = pivot.Left;
171+
pivot.Left = parent;
172+
return pivot;
173+
}
174+
175+
private static Node RotateLl(Node parent)
176+
{
177+
var pivot = parent.Left;
178+
parent.Left = pivot.Right;
179+
pivot.Right = parent;
180+
return pivot;
181+
}
182+
183+
private static Node RotateLr(Node parent)
184+
{
185+
var pivot = parent.Left;
186+
parent.Left = RotateRr(pivot);
187+
return RotateLl(parent);
188+
}
189+
190+
private static Node RotateRl(Node parent)
191+
{
192+
var pivot = parent.Right;
193+
parent.Right = RotateLl(pivot);
194+
return RotateRr(parent);
195+
}
196+
197+
private static int GetBalanceFactor(Node? node)
198+
{
199+
if (node == null)
200+
return 0;
201+
202+
return GetHeight(node.Left) - GetHeight(node.Right);
93203
}
94204

95-
public void PrintTree(Node root)
205+
private static int GetHeight(Node? current)
96206
{
97-
if (root == null)
207+
if (current == null)
208+
return 0;
209+
210+
var left = GetHeight(current.Left);
211+
var right = GetHeight(current.Right);
212+
return Math.Max(left, right) + 1;
213+
}
214+
215+
private int GetDepth()
216+
{
217+
return GetDepth(_root);
218+
}
219+
220+
private static int GetDepth(Node? parent)
221+
{
222+
return parent == null ? 0 : Math.Max(GetDepth(parent.Left), GetDepth(parent.Right)) + 1;
223+
}
224+
225+
public void TraversePreOrder()
226+
{
227+
Console.WriteLine($"TraversePreOrder(LDR) with Depth {GetDepth()}: ");
228+
TraversePreOrder(_root);
229+
Console.WriteLine();
230+
}
231+
232+
public void TraverseInOrder()
233+
{
234+
Console.WriteLine($"TraverseInOrder(LDR) with Depth {GetDepth()}: ");
235+
TraverseInOrder(_root);
236+
Console.WriteLine();
237+
}
238+
239+
public void TraversePostOrder()
240+
{
241+
Console.WriteLine($"TraversePostOrder(LDR) with Depth {GetDepth()}: ");
242+
TraversePostOrder(_root);
243+
Console.WriteLine();
244+
}
245+
246+
private static void TraversePreOrder(Node? parent)
247+
{
248+
if (parent is null)
98249
return;
99-
if (root != null)
250+
251+
Console.Write(parent.Data + " ");
252+
TraversePreOrder(parent.Left);
253+
TraversePreOrder(parent.Right);
254+
}
255+
256+
private static void TraverseInOrder(Node? parent)
257+
{
258+
while (true)
100259
{
101-
PrintTree(root.Left);
102-
Console.Write(root.Data + " ");
103-
PrintTree(root.Left);
260+
if (parent == null) return;
261+
262+
TraverseInOrder(parent.Left);
263+
Console.Write(parent.Data + " ");
264+
parent = parent.Right;
104265
}
105266
}
267+
268+
private static void TraversePostOrder(Node? parent)
269+
{
270+
if (parent is null)
271+
return;
272+
273+
TraversePostOrder(parent.Left);
274+
TraversePostOrder(parent.Right);
275+
Console.Write(parent.Data + " ");
276+
}
106277
}

0 commit comments

Comments
 (0)