1
1
using System ;
2
2
using System . Collections . Generic ;
3
+ using System . Linq ;
3
4
4
5
namespace BinarySearchTree
5
6
{
7
+ /// <summary>
8
+ /// Represents a node in a (binary) tree.
9
+ /// </summary>
10
+ /// <typeparam name="T">The payload of the node as generic type.</typeparam>
6
11
public class Node < T >
7
12
{
13
+ /// <summary>
14
+ /// The payload of the node.
15
+ /// </summary>
8
16
public T Value { get ; set ; }
9
17
18
+ /// <summary>
19
+ /// An item with lower a value than the value of this node will become a LeftNode.
20
+ /// </summary>
10
21
public Node < T > LeftNode ;
22
+ /// <summary>
23
+ /// An item with higher a value than the value of this node will become a RightNode.
24
+ /// </summary>
11
25
public Node < T > RightNode ;
12
26
27
+ /// <summary>
28
+ /// Creates a new Node.
29
+ /// </summary>
30
+ /// <param name="value">Payload of the new node</param>
13
31
public Node ( T value )
14
32
{
15
33
Value = value ;
16
34
}
17
35
}
18
36
19
- public class BinarySearchTree < T > where T : IComparable
37
+
38
+ /// <summary>
39
+ /// Data structure that stores items and allows fast lookup, insertion and deletion.
40
+ /// </summary>
41
+ /// <typeparam name="T">The type of the trees items.</typeparam>
42
+ public class BinarySearchTree < T > where T : IComparable < T >
20
43
{
21
44
private Node < T > _globalRoot ;
22
- public Node < T > InsertNode ( Node < T > root , T value )
45
+ /// <summary>
46
+ /// Inserts a new node in a existing tree
47
+ /// </summary>
48
+ /// <param name="root">The root node of the tree</param>
49
+ /// <param name="value">Value to be inserted into the tree</param>
50
+ /// <returns></returns>
51
+ /*public Node<T> InsertNode(ref Node<T> root, T value)
23
52
{
24
53
if (root == null)
25
54
{
26
55
root = new Node<T>(value);
27
- if ( _globalRoot == null )
56
+ if (_globalRoot == null)
28
57
_globalRoot = root;
29
58
}
30
59
else
60
+ {
61
+ if (value.CompareTo(root.Value) <= 0)
62
+ {
63
+ root.LeftNode = InsertNode(root.LeftNode, value);
64
+ }
65
+ else if (value.CompareTo(root.Value) > 0) //Items with the same value are ignored, use >= to insert them into the three
66
+ {
67
+ root.RightNode = InsertNode(root.RightNode, value);
68
+ }
69
+ }
70
+ return root;
71
+ }*/
72
+
73
+
74
+ public void InsertNode ( T value )
75
+ {
76
+ if ( _globalRoot == null )
77
+ {
78
+ _globalRoot = new Node < T > ( value ) ;
79
+ }
80
+ else
81
+ {
82
+ InsertNode ( _globalRoot , value ) ;
83
+ }
84
+ }
85
+
86
+ private static Node < T > InsertNode ( Node < T > root , T value )
87
+ {
88
+ if ( root == null )
89
+ {
90
+ root = new Node < T > ( value ) ;
91
+ }
92
+ else
31
93
{
32
94
if ( value . CompareTo ( root . Value ) <= 0 )
33
95
{
34
96
root . LeftNode = InsertNode ( root . LeftNode , value ) ;
35
97
}
36
- else if ( value . CompareTo ( root . Value ) >= 0 )
98
+ else if ( value . CompareTo ( root . Value ) > 0 ) //Items with the same value are ignored, use >= to insert them into the three
37
99
{
38
100
root . RightNode = InsertNode ( root . RightNode , value ) ;
39
101
}
40
102
}
41
103
return root ;
42
104
}
43
105
44
- public IEnumerable < T > PreorderTraverseTree ( Node < T > root )
106
+ /// <summary>
107
+ /// Preorder traversal of the tree. Visites the root, then visits the left sub-tree, after that it visits the right sub-tree.
108
+ /// </summary>
109
+ /// <returns></returns>
110
+ public IEnumerable < T > PreorderTraverseTree ( )
111
+ {
112
+ if ( _globalRoot == null ) yield break ;
113
+
114
+ foreach ( var node in PreorderTraverseTree ( _globalRoot ) )
115
+ yield return node ;
116
+ }
117
+
118
+ private static IEnumerable < T > PreorderTraverseTree ( Node < T > root )
45
119
{
46
120
if ( root == null ) yield break ;
47
121
yield return root . Value ;
@@ -56,7 +130,43 @@ public IEnumerable<T> PreorderTraverseTree(Node<T> root)
56
130
}
57
131
}
58
132
59
- public void DeleteNode ( ref Node < T > root , T value )
133
+ /// <summary>
134
+ /// Inorder traversal of the tree.
135
+ /// </summary>
136
+ /// <returns></returns>
137
+ public IEnumerable < T > InOrderTraverseTree ( )
138
+ {
139
+ if ( _globalRoot == null ) yield break ;
140
+
141
+ foreach ( var node in InOrderTraverseTree ( _globalRoot ) )
142
+ yield return node ;
143
+ }
144
+
145
+ private static IEnumerable < T > InOrderTraverseTree ( Node < T > root )
146
+ {
147
+ if ( root == null ) yield break ;
148
+ foreach ( var v in InOrderTraverseTree ( root . LeftNode ) )
149
+ {
150
+ yield return v ;
151
+ }
152
+ yield return root . Value ;
153
+ foreach ( var v in InOrderTraverseTree ( root . RightNode ) )
154
+ {
155
+ yield return v ;
156
+ }
157
+ }
158
+
159
+ /// <summary>
160
+ /// Deletes a node from the tree.
161
+ /// </summary>
162
+ /// <param name="value">Value of the node which is to be deleted.</param>
163
+ public void DeleteNode ( T value )
164
+ {
165
+ if ( _globalRoot == null ) return ;
166
+ DeleteNode ( ref _globalRoot , value ) ;
167
+ }
168
+
169
+ private void DeleteNode ( ref Node < T > root , T value )
60
170
{
61
171
if ( root == null ) return ;
62
172
if ( root . Value . Equals ( value ) )
@@ -69,14 +179,46 @@ public void DeleteNode(ref Node<T> root, T value)
69
179
}
70
180
}
71
181
72
- private Node < T > Delete ( ref Node < T > root )
182
+ /// <summary>
183
+ /// Traverses the tree to find and return a Node with a certain value.
184
+ /// </summary>
185
+ /// <param name="value">The value to search for</param>
186
+ /// <returns></returns>
187
+ public T FindNode ( T value )
188
+ {
189
+ var res = FindNode ( _globalRoot , value ) ;
190
+
191
+ return res . Value ;
192
+ }
193
+
194
+ private static Node < T > FindNode ( Node < T > root , T value )
195
+ {
196
+ Node < T > res = null ;
197
+ if ( root . LeftNode != null )
198
+ res = FindNode ( root . LeftNode , value ) ;
199
+
200
+ if ( value . CompareTo ( root . Value ) == 0 )
201
+ return root ;
202
+
203
+ if ( res == null && root . RightNode != null )
204
+ res = FindNode ( root . RightNode , value ) ;
205
+
206
+ return res ;
207
+ }
208
+
209
+ /// <summary>
210
+ /// Only use with custom implementations of DeleteNode!
211
+ /// </summary>
212
+ /// <param name="root">The root node of the tree.</param>
213
+ /// <returns></returns>
214
+ public Node < T > Delete ( ref Node < T > root )
73
215
{
74
216
var tempValue = default ( T ) ;
75
217
76
- if ( _globalRoot == root )
218
+ if ( _globalRoot == root && root . LeftNode == null && root . RightNode == null )
77
219
{
78
- //Deletion of root element is not allowed;
79
- return root ;
220
+ //Deletion of root element is allowed - to for forbid it, return root
221
+ return null ;
80
222
}
81
223
if ( root . LeftNode == null && root . RightNode == null )
82
224
{
@@ -111,5 +253,29 @@ private static void Replace(ref Node<T> root, ref T newValue)
111
253
Replace ( ref root . LeftNode , ref newValue ) ;
112
254
}
113
255
}
256
+
257
+ public BinarySearchTree < T > BalancedTree ( )
258
+ {
259
+ var balanced = new BinarySearchTree < T > ( ) ;
260
+ var inorder = InOrderTraverseTree ( ) . ToArray ( ) ;
261
+
262
+ balanced . _globalRoot = BalanceTree ( inorder , 0 , inorder . Length - 1 ) ;
263
+
264
+ return balanced ;
265
+ }
266
+
267
+ private static Node < T > BalanceTree ( IReadOnlyList < T > inorder , int startIndex , int endIndex )
268
+ {
269
+ if ( startIndex > endIndex ) return null ;
270
+
271
+ var middIndex = ( startIndex + endIndex ) / 2 ;
272
+
273
+ var root = new Node < T > ( inorder [ middIndex ] ) ;
274
+
275
+ root . LeftNode = BalanceTree ( inorder , startIndex , middIndex - 1 ) ;
276
+ root . RightNode = BalanceTree ( inorder , middIndex + 1 , endIndex ) ;
277
+
278
+ return root ;
279
+ }
114
280
}
115
281
}
0 commit comments