Skip to content

Commit 9fd1ec8

Browse files
committed
optimize bst item position for insertion/deletion
1 parent edb0809 commit 9fd1ec8

File tree

5 files changed

+42
-31
lines changed

5 files changed

+42
-31
lines changed

src/Advanced.Algorithms/Advanced.Algorithms.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<AssemblyOriginatorKeyFile>StrongNameKey.snk</AssemblyOriginatorKeyFile>
99
<DelaySign>False</DelaySign>
1010
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
11+
<LangVersion>default</LangVersion>
1112
</PropertyGroup>
1213

1314
<ItemGroup>
@@ -17,12 +18,13 @@
1718
<EmbeddedResource Remove="DynamicProgramming\**" />
1819
<None Remove="Binary\**" />
1920
<None Remove="DynamicProgramming\**" />
21+
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
2022
</ItemGroup>
2123

2224
<ItemGroup>
2325
<Compile Include="Binary\BaseConversion.cs" />
2426
<Compile Include="Binary\Logarithm.cs" />
2527
<Compile Include="Binary\GCD.cs" />
2628
</ItemGroup>
27-
29+
2830
</Project>

src/Advanced.Algorithms/DataStructures/Tree/IntervalTree.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,12 +304,10 @@ internal void Insert(OneDimentionalInterval<T> newInterval)
304304
if (existing != null)
305305
{
306306
existing.Value.End.Add(newInterval.End[0]);
307-
308307
}
309308
else
310309
{
311-
312-
existing = redBlackTree.InsertAndReturnNode(newInterval);
310+
existing = redBlackTree.InsertAndReturnNode(newInterval).Item1;
313311
}
314312
updateMax(existing);
315313
Count++;

src/Advanced.Algorithms/DataStructures/Tree/RedBlackTree.cs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public bool HasItem(T value)
5959
return nodeLookUp.ContainsKey(value);
6060
}
6161

62-
return find(value) != null;
62+
return find(value).Item1 != null;
6363
}
6464

6565
/// <summary>
@@ -117,7 +117,7 @@ public T ElementAt(int index)
117117
//O(log(n)) worst O(n) for unbalanced tree
118118
internal RedBlackTreeNode<T> FindNode(T value)
119119
{
120-
return Root == null ? null : find(value);
120+
return Root == null ? null : find(value).Item1;
121121
}
122122

123123
//O(log(n)) worst O(n) for unbalanced tree
@@ -129,14 +129,15 @@ internal bool Exists(T value)
129129
//find the node with the given identifier among descendants of parent and parent
130130
//uses pre-order traversal
131131
//O(log(n)) worst O(n) for unbalanced tree
132-
private RedBlackTreeNode<T> find(T value)
132+
private (RedBlackTreeNode<T>, int) find(T value)
133133
{
134134
if (nodeLookUp != null)
135135
{
136-
return nodeLookUp[value] as RedBlackTreeNode<T>;
136+
return (nodeLookUp[value] as RedBlackTreeNode<T>, Root.Position(value));
137137
}
138138

139-
return Root.Find<T>(value) as RedBlackTreeNode<T>;
139+
var result = Root.Find(value);
140+
return (result.Item1 as RedBlackTreeNode<T>, result.Item2);
140141
}
141142

142143
/// <summary>
@@ -146,13 +147,13 @@ private RedBlackTreeNode<T> find(T value)
146147
public int Insert(T value)
147148
{
148149
var node = InsertAndReturnNode(value);
149-
return Root.Position(value);
150+
return node.Item2;
150151
}
151152

152153
/// <summary>
153154
/// Time complexity: O(log(n))
154155
/// </summary>
155-
internal RedBlackTreeNode<T> InsertAndReturnNode(T value)
156+
internal (RedBlackTreeNode<T>, int) InsertAndReturnNode(T value)
156157
{
157158
//empty tree
158159
if (Root == null)
@@ -163,39 +164,43 @@ internal RedBlackTreeNode<T> InsertAndReturnNode(T value)
163164
nodeLookUp[value] = Root;
164165
}
165166

166-
return Root;
167+
return (Root, 0);
167168
}
168169

169-
var newNode = insert(Root, value);
170+
var newNode = Insert(Root, value);
170171

171172
if (nodeLookUp != null)
172173
{
173-
nodeLookUp[value] = newNode;
174+
nodeLookUp[value] = newNode.Item1;
174175
}
175176

176177
return newNode;
177178
}
178179

179180
//O(log(n)) always
180-
private RedBlackTreeNode<T> insert(RedBlackTreeNode<T> currentNode, T newNodeValue)
181+
private (RedBlackTreeNode<T>, int) Insert(RedBlackTreeNode<T> currentNode, T newNodeValue)
181182
{
183+
var insertionPosition = 0;
184+
182185
while (true)
183186
{
184187
var compareResult = currentNode.Value.CompareTo(newNodeValue);
185188

186189
//current node is less than new item
187190
if (compareResult < 0)
188191
{
192+
insertionPosition += (currentNode.Left != null ? currentNode.Left.Count : 0) + 1;
193+
189194
//no right child
190195
if (currentNode.Right == null)
191196
{
192197
//insert
193198
var node = currentNode.Right = new RedBlackTreeNode<T>(currentNode, newNodeValue);
194199
balanceInsertion(currentNode.Right);
195-
return node;
200+
return (node, insertionPosition);
196201
}
197202

198-
currentNode = currentNode.Right;
203+
currentNode = currentNode.Right;
199204
}
200205
//current node is greater than new node
201206
else if (compareResult > 0)
@@ -205,7 +210,7 @@ private RedBlackTreeNode<T> insert(RedBlackTreeNode<T> currentNode, T newNodeVal
205210
//insert
206211
var node = currentNode.Left = new RedBlackTreeNode<T>(currentNode, newNodeValue);
207212
balanceInsertion(currentNode.Left);
208-
return node;
213+
return (node, insertionPosition);
209214
}
210215

211216
currentNode = currentNode.Left;
@@ -356,14 +361,14 @@ public int Delete(T value)
356361

357362
var node = find(value);
358363

359-
if (node == null)
364+
if (node.Item1 == null)
360365
{
361366
return -1;
362367
}
363368

364-
var position = Root.Position(value);
369+
var position = node.Item2;
365370

366-
delete(node);
371+
delete(node.Item1);
367372

368373
if (nodeLookUp != null)
369374
{
@@ -830,8 +835,8 @@ public T NextHigher(T value)
830835

831836
internal void Swap(T value1, T value2)
832837
{
833-
var node1 = find(value1);
834-
var node2 = find(value2);
838+
var node1 = find(value1).Item1;
839+
var node2 = find(value2).Item1;
835840

836841
if (node1 == null || node2 == null)
837842
{

src/Advanced.Algorithms/DataStructures/Tree/Shared/BSTExtensions.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,23 @@ internal static class BSTExtensions
88
//find the node with the given identifier among descendants of parent and parent
99
//uses pre-order traversal
1010
//O(log(n)) worst O(n) for unbalanced tree
11-
internal static BSTNodeBase<T> Find<T>(this BSTNodeBase<T> current, T value) where T : IComparable
11+
internal static (BSTNodeBase<T>, int) Find<T>(this BSTNodeBase<T> current, T value) where T : IComparable
1212
{
13+
int position = 0;
14+
1315
while (true)
1416
{
1517
if (current == null)
1618
{
17-
return null;
19+
return (null, -1);
1820
}
1921

2022
var compareResult = current.Value.CompareTo(value);
2123

2224
if (compareResult == 0)
2325
{
24-
return current;
26+
position += (current.Left != null ? current.Left.Count : 0);
27+
return (current, position);
2528
}
2629

2730
if (compareResult > 0)
@@ -30,7 +33,8 @@ internal static BSTNodeBase<T> Find<T>(this BSTNodeBase<T> current, T value) whe
3033
}
3134
else
3235
{
33-
current = current.Right;
36+
position += (current.Left != null ? current.Left.Count : 0) + 1;
37+
current = current.Right;
3438
}
3539
}
3640
}

tests/Advanced.Algorithms.Tests/DataStructures/Tree/RedBlackTree_Tests.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ public void RedBlackTree_Accuracy_Test()
6868

6969
for (int i = 0; i < nodeCount; i++)
7070
{
71-
tree.Insert(randomNumbers[i]);
71+
var index = tree.Insert(randomNumbers[i]);
72+
Assert.AreEqual(index, tree.IndexOf(randomNumbers[i]));
7273
Assert.IsTrue(tree.HasItem(randomNumbers[i]));
7374
Assert.IsTrue(tree.Root.IsBinarySearchTree(int.MinValue, int.MaxValue));
7475
tree.Root.VerifyCount();
@@ -98,17 +99,18 @@ public void RedBlackTree_Accuracy_Test()
9899

99100
for (int i = 0; i < nodeCount; i++)
100101
{
101-
if(rnd.NextDouble() >= 0.5)
102+
if (rnd.NextDouble() >= 0.5)
102103
{
103-
tree.Delete(randomNumbers[i]);
104+
var index = tree.IndexOf(randomNumbers[i]);
105+
Assert.AreEqual(index, tree.Delete(randomNumbers[i]));
104106
}
105107
else
106108
{
107109
var index = tree.IndexOf(randomNumbers[i]);
108110
Assert.AreEqual(tree.ElementAt(index), randomNumbers[i]);
109111
tree.RemoveAt(index);
110112
}
111-
113+
112114
Assert.IsTrue(tree.Root.IsBinarySearchTree(int.MinValue, int.MaxValue));
113115
tree.Root.VerifyCount();
114116
var actualHeight = tree.Root.GetHeight();

0 commit comments

Comments
 (0)