22using System . Collections ;
33using System . Collections . Generic ;
44using System . Linq ;
5+ using System . Reflection ;
56
67namespace Advanced . Algorithms . DataStructures
78{
@@ -10,20 +11,26 @@ namespace Advanced.Algorithms.DataStructures
1011 /// </summary>
1112 public class RedBlackTree < T > : IEnumerable < T > where T : IComparable
1213 {
13- //if enabled, lookup will fasten deletion/insertion/exists operations.
14- private readonly Dictionary < T , BSTNodeBase < T > > nodeLookUp ;
15-
1614 internal RedBlackTreeNode < T > Root { get ; set ; }
1715
16+ //if enabled, lookup will fasten deletion/insertion/exists operations.
17+ internal readonly Dictionary < T , BSTNodeBase < T > > NodeLookUp ;
18+
1819 public int Count => Root == null ? 0 : Root . Count ;
1920
2021 /// <param name="enableNodeLookUp">Enabling lookup will fasten deletion/insertion/exists operations
2122 /// 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 )
2325 {
2426 if ( enableNodeLookUp )
2527 {
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 ) ;
2734 }
2835 }
2936
@@ -34,7 +41,9 @@ public RedBlackTree(bool enableNodeLookUp = false)
3441 /// <param name="sortedCollection">The sorted initial collection.</param>
3542 /// <param name="enableNodeLookUp">Enabling lookup will fasten deletion/insertion/exists operations
3643 /// 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 )
3847 {
3948 BSTHelpers . ValidateSortedCollection ( sortedCollection ) ;
4049 var nodes = sortedCollection . Select ( x => new RedBlackTreeNode < T > ( null , x ) ) . ToArray ( ) ;
@@ -44,15 +53,13 @@ public RedBlackTree(IEnumerable<T> sortedCollection, bool enableNodeLookUp = fal
4453
4554 if ( enableNodeLookUp )
4655 {
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+ }
5060
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+ }
5663 }
5764
5865 /// <summary>
@@ -65,12 +72,12 @@ public bool HasItem(T value)
6572 return false ;
6673 }
6774
68- if ( nodeLookUp != null )
75+ if ( NodeLookUp != null )
6976 {
70- return nodeLookUp . ContainsKey ( value ) ;
77+ return NodeLookUp . ContainsKey ( value ) ;
7178 }
7279
73- return find ( value ) . Item1 != null ;
80+ return Find ( value ) . Item1 != null ;
7481 }
7582
7683 /// <summary>
@@ -125,28 +132,25 @@ public T ElementAt(int index)
125132 return Root . KthSmallest ( index ) . Value ;
126133 }
127134
128- //O(log(n)) worst O(n) for unbalanced tree
129135 internal RedBlackTreeNode < T > FindNode ( T value )
130136 {
131- return Root == null ? null : find ( value ) . Item1 ;
137+ return Root == null ? null : Find ( value ) . Item1 ;
132138 }
133139
134- //O(log(n)) worst O(n) for unbalanced tree
135140 internal bool Exists ( T value )
136141 {
137142 return FindNode ( value ) != null ;
138143 }
139144
140145 //find the node with the given identifier among descendants of parent and parent
141146 //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 )
144148 {
145- if ( nodeLookUp != null )
149+ if ( NodeLookUp != null )
146150 {
147- if ( nodeLookUp . ContainsKey ( value ) )
151+ if ( NodeLookUp . ContainsKey ( value ) )
148152 {
149- var node = ( nodeLookUp [ value ] as RedBlackTreeNode < T > ) ;
153+ var node = ( NodeLookUp [ value ] as RedBlackTreeNode < T > ) ;
150154 return ( node , Root . Position ( value ) ) ;
151155 }
152156
@@ -176,19 +180,19 @@ public int Insert(T value)
176180 if ( Root == null )
177181 {
178182 Root = new RedBlackTreeNode < T > ( null , value ) { NodeColor = RedBlackTreeNodeColor . Black } ;
179- if ( nodeLookUp != null )
183+ if ( NodeLookUp != null )
180184 {
181- nodeLookUp [ value ] = Root ;
185+ NodeLookUp [ value ] = Root ;
182186 }
183187
184188 return ( Root , 0 ) ;
185189 }
186190
187191 var newNode = insert ( Root , value ) ;
188192
189- if ( nodeLookUp != null )
193+ if ( NodeLookUp != null )
190194 {
191- nodeLookUp [ value ] = newNode . Item1 ;
195+ NodeLookUp [ value ] = newNode . Item1 ;
192196 }
193197
194198 return newNode ;
@@ -376,7 +380,7 @@ public int Delete(T value)
376380 return - 1 ;
377381 }
378382
379- var node = find ( value ) ;
383+ var node = Find ( value ) ;
380384
381385 if ( node . Item1 == null )
382386 {
@@ -387,9 +391,9 @@ public int Delete(T value)
387391
388392 delete ( node . Item1 ) ;
389393
390- if ( nodeLookUp != null )
394+ if ( NodeLookUp != null )
391395 {
392- nodeLookUp . Remove ( value ) ;
396+ NodeLookUp . Remove ( value ) ;
393397 }
394398
395399 return position ;
@@ -412,9 +416,9 @@ public T RemoveAt(int index)
412416
413417 delete ( node ) ;
414418
415- if ( nodeLookUp != null )
419+ if ( NodeLookUp != null )
416420 {
417- nodeLookUp . Remove ( deletedValue ) ;
421+ NodeLookUp . Remove ( deletedValue ) ;
418422 }
419423
420424 return node . Value ;
@@ -458,10 +462,10 @@ private void delete(RedBlackTreeNode<T> node)
458462 {
459463 var maxLeftNode = findMax ( node . Left ) ;
460464
461- if ( nodeLookUp != null )
465+ if ( NodeLookUp != null )
462466 {
463- nodeLookUp [ node . Value ] = maxLeftNode ;
464- nodeLookUp [ maxLeftNode . Value ] = node ;
467+ NodeLookUp [ node . Value ] = maxLeftNode ;
468+ NodeLookUp [ maxLeftNode . Value ] = node ;
465469 }
466470
467471 node . Value = maxLeftNode . Value ;
@@ -853,28 +857,6 @@ public T NextHigher(T value)
853857 return next != null ? next . Value : default ( T ) ;
854858 }
855859
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-
878860 /// <summary>
879861 /// Descending enumerable.
880862 /// </summary>
0 commit comments