2
2
using System . Collections ;
3
3
using System . Collections . Generic ;
4
4
using System . Linq ;
5
+ using System . Reflection ;
5
6
6
7
namespace Advanced . Algorithms . DataStructures
7
8
{
@@ -10,20 +11,26 @@ namespace Advanced.Algorithms.DataStructures
10
11
/// </summary>
11
12
public class RedBlackTree < T > : IEnumerable < T > where T : IComparable
12
13
{
13
- //if enabled, lookup will fasten deletion/insertion/exists operations.
14
- private readonly Dictionary < T , BSTNodeBase < T > > nodeLookUp ;
15
-
16
14
internal RedBlackTreeNode < T > Root { get ; set ; }
17
15
16
+ //if enabled, lookup will fasten deletion/insertion/exists operations.
17
+ internal readonly Dictionary < T , BSTNodeBase < T > > NodeLookUp ;
18
+
18
19
public int Count => Root == null ? 0 : Root . Count ;
19
20
20
21
/// <param name="enableNodeLookUp">Enabling lookup will fasten deletion/insertion/exists operations
21
22
/// at the cost of additional space.</param>
22
- public RedBlackTree ( bool enableNodeLookUp = false )
23
+ /// <param name="equalityComparer">Provide equality comparer for node lookup if enabled (required when T is not a value type).</param>
24
+ public RedBlackTree ( bool enableNodeLookUp = false , IEqualityComparer < T > equalityComparer = null )
23
25
{
24
26
if ( enableNodeLookUp )
25
27
{
26
- nodeLookUp = new Dictionary < T , BSTNodeBase < T > > ( ) ;
28
+ if ( ! typeof ( T ) . GetTypeInfo ( ) . IsValueType && equalityComparer == null )
29
+ {
30
+ throw new ArgumentException ( "equalityComparer parameter is required when node lookup us enabled and T is not a value type." ) ;
31
+ }
32
+
33
+ NodeLookUp = new Dictionary < T , BSTNodeBase < T > > ( equalityComparer ) ;
27
34
}
28
35
}
29
36
@@ -34,7 +41,9 @@ public RedBlackTree(bool enableNodeLookUp = false)
34
41
/// <param name="sortedCollection">The sorted initial collection.</param>
35
42
/// <param name="enableNodeLookUp">Enabling lookup will fasten deletion/insertion/exists operations
36
43
/// at the cost of additional space.</param>
37
- public RedBlackTree ( IEnumerable < T > sortedCollection , bool enableNodeLookUp = false )
44
+ /// <param name="equalityComparer">Provide equality comparer for node lookup if enabled (required when T is not a value type).</param>
45
+ public RedBlackTree ( IEnumerable < T > sortedCollection , bool enableNodeLookUp = false ,
46
+ IEqualityComparer < T > equalityComparer = null )
38
47
{
39
48
BSTHelpers . ValidateSortedCollection ( sortedCollection ) ;
40
49
var nodes = sortedCollection . Select ( x => new RedBlackTreeNode < T > ( null , x ) ) . ToArray ( ) ;
@@ -44,15 +53,13 @@ public RedBlackTree(IEnumerable<T> sortedCollection, bool enableNodeLookUp = fal
44
53
45
54
if ( enableNodeLookUp )
46
55
{
47
- nodeLookUp = nodes . ToDictionary ( x => x . Value , x => x as BSTNodeBase < T > ) ;
48
- }
49
- }
56
+ if ( ! typeof ( T ) . GetTypeInfo ( ) . IsValueType && equalityComparer == null )
57
+ {
58
+ throw new ArgumentException ( "equalityComparer parameter is required when node lookup us enabled and T is not a value type." ) ;
59
+ }
50
60
51
- ///Special (internal only) constructor for Bentley-Ottmann sweep line algorithm for fast line swap.
52
- /// <param name="equalityComparer">Provide custom IEquality comparer for node lookup dictionary.</param>
53
- internal RedBlackTree ( IEqualityComparer < T > equalityComparer )
54
- {
55
- nodeLookUp = new Dictionary < T , BSTNodeBase < T > > ( equalityComparer ) ;
61
+ NodeLookUp = nodes . ToDictionary ( x => x . Value , x => x as BSTNodeBase < T > ) ;
62
+ }
56
63
}
57
64
58
65
/// <summary>
@@ -65,12 +72,12 @@ public bool HasItem(T value)
65
72
return false ;
66
73
}
67
74
68
- if ( nodeLookUp != null )
75
+ if ( NodeLookUp != null )
69
76
{
70
- return nodeLookUp . ContainsKey ( value ) ;
77
+ return NodeLookUp . ContainsKey ( value ) ;
71
78
}
72
79
73
- return find ( value ) . Item1 != null ;
80
+ return Find ( value ) . Item1 != null ;
74
81
}
75
82
76
83
/// <summary>
@@ -125,28 +132,25 @@ public T ElementAt(int index)
125
132
return Root . KthSmallest ( index ) . Value ;
126
133
}
127
134
128
- //O(log(n)) worst O(n) for unbalanced tree
129
135
internal RedBlackTreeNode < T > FindNode ( T value )
130
136
{
131
- return Root == null ? null : find ( value ) . Item1 ;
137
+ return Root == null ? null : Find ( value ) . Item1 ;
132
138
}
133
139
134
- //O(log(n)) worst O(n) for unbalanced tree
135
140
internal bool Exists ( T value )
136
141
{
137
142
return FindNode ( value ) != null ;
138
143
}
139
144
140
145
//find the node with the given identifier among descendants of parent and parent
141
146
//uses pre-order traversal
142
- //O(log(n)) worst O(n) for unbalanced tree
143
- private ( RedBlackTreeNode < T > , int ) find ( T value )
147
+ internal ( RedBlackTreeNode < T > , int ) Find ( T value )
144
148
{
145
- if ( nodeLookUp != null )
149
+ if ( NodeLookUp != null )
146
150
{
147
- if ( nodeLookUp . ContainsKey ( value ) )
151
+ if ( NodeLookUp . ContainsKey ( value ) )
148
152
{
149
- var node = ( nodeLookUp [ value ] as RedBlackTreeNode < T > ) ;
153
+ var node = ( NodeLookUp [ value ] as RedBlackTreeNode < T > ) ;
150
154
return ( node , Root . Position ( value ) ) ;
151
155
}
152
156
@@ -176,19 +180,19 @@ public int Insert(T value)
176
180
if ( Root == null )
177
181
{
178
182
Root = new RedBlackTreeNode < T > ( null , value ) { NodeColor = RedBlackTreeNodeColor . Black } ;
179
- if ( nodeLookUp != null )
183
+ if ( NodeLookUp != null )
180
184
{
181
- nodeLookUp [ value ] = Root ;
185
+ NodeLookUp [ value ] = Root ;
182
186
}
183
187
184
188
return ( Root , 0 ) ;
185
189
}
186
190
187
191
var newNode = insert ( Root , value ) ;
188
192
189
- if ( nodeLookUp != null )
193
+ if ( NodeLookUp != null )
190
194
{
191
- nodeLookUp [ value ] = newNode . Item1 ;
195
+ NodeLookUp [ value ] = newNode . Item1 ;
192
196
}
193
197
194
198
return newNode ;
@@ -376,7 +380,7 @@ public int Delete(T value)
376
380
return - 1 ;
377
381
}
378
382
379
- var node = find ( value ) ;
383
+ var node = Find ( value ) ;
380
384
381
385
if ( node . Item1 == null )
382
386
{
@@ -387,9 +391,9 @@ public int Delete(T value)
387
391
388
392
delete ( node . Item1 ) ;
389
393
390
- if ( nodeLookUp != null )
394
+ if ( NodeLookUp != null )
391
395
{
392
- nodeLookUp . Remove ( value ) ;
396
+ NodeLookUp . Remove ( value ) ;
393
397
}
394
398
395
399
return position ;
@@ -412,9 +416,9 @@ public T RemoveAt(int index)
412
416
413
417
delete ( node ) ;
414
418
415
- if ( nodeLookUp != null )
419
+ if ( NodeLookUp != null )
416
420
{
417
- nodeLookUp . Remove ( deletedValue ) ;
421
+ NodeLookUp . Remove ( deletedValue ) ;
418
422
}
419
423
420
424
return node . Value ;
@@ -458,10 +462,10 @@ private void delete(RedBlackTreeNode<T> node)
458
462
{
459
463
var maxLeftNode = findMax ( node . Left ) ;
460
464
461
- if ( nodeLookUp != null )
465
+ if ( NodeLookUp != null )
462
466
{
463
- nodeLookUp [ node . Value ] = maxLeftNode ;
464
- nodeLookUp [ maxLeftNode . Value ] = node ;
467
+ NodeLookUp [ node . Value ] = maxLeftNode ;
468
+ NodeLookUp [ maxLeftNode . Value ] = node ;
465
469
}
466
470
467
471
node . Value = maxLeftNode . Value ;
@@ -853,28 +857,6 @@ public T NextHigher(T value)
853
857
return next != null ? next . Value : default ( T ) ;
854
858
}
855
859
856
- ///Special (internal only) method for Bentley-Ottmann sweep line algorithm.
857
- internal void Swap ( T value1 , T value2 )
858
- {
859
- var node1 = find ( value1 ) . Item1 ;
860
- var node2 = find ( value2 ) . Item1 ;
861
-
862
- if ( node1 == null || node2 == null )
863
- {
864
- throw new Exception ( "Value1, Value2 or both was not found in this BST." ) ;
865
- }
866
-
867
- var tmp = node1 . Value ;
868
- node1 . Value = node2 . Value ;
869
- node2 . Value = tmp ;
870
-
871
- if ( nodeLookUp != null )
872
- {
873
- nodeLookUp [ node1 . Value ] = node1 ;
874
- nodeLookUp [ node2 . Value ] = node2 ;
875
- }
876
- }
877
-
878
860
/// <summary>
879
861
/// Descending enumerable.
880
862
/// </summary>
0 commit comments