Skip to content

Commit 43d0acb

Browse files
committed
Testing and fixing of: BinarySearchTreeMap and RedBlackTreeMap.
1 parent ee93be8 commit 43d0acb

9 files changed

+574
-15
lines changed

Diff for: DataStructures/Trees/BinarySearchTreeMap.cs

+6-6
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ public virtual void Update(TKey key, TValue newValue)
468468
var node = _findNode(Root, key);
469469

470470
if (node == null)
471-
throw new KeyNotFoundException();
471+
throw new KeyNotFoundException("Key doesn't exist in tree.");
472472

473473
node.Value = newValue;
474474
}
@@ -482,11 +482,11 @@ public virtual void Remove(TKey key)
482482
throw new Exception("Tree is empty.");
483483

484484
var node = _findNode(Root, key);
485-
bool status = _remove(node);
486485

487-
// If the element was found, remove it.
488-
if (status == false)
489-
throw new Exception("Item was not found.");
486+
if (node == null)
487+
throw new KeyNotFoundException("Key doesn't exist in tree.");
488+
489+
_remove(node);
490490
}
491491

492492
/// <summary>
@@ -599,7 +599,7 @@ public virtual KeyValuePair<TKey, TValue> Find(TKey key)
599599
if (node != null)
600600
return new KeyValuePair<TKey, TValue>(node.Key, node.Value);
601601
else
602-
throw new Exception("Item was not found.");
602+
throw new KeyNotFoundException("Item was not found.");
603603
}
604604

605605
/// <summary>

Diff for: DataStructures/Trees/BinarySearchTreeMapNode.cs

+1-5
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,7 @@ public class BSTMapNode<TKey, TValue> : IComparable<BSTMapNode<TKey, TValue>> wh
1313
private BSTMapNode<TKey, TValue> _left;
1414
private BSTMapNode<TKey, TValue> _right;
1515

16-
public BSTMapNode()
17-
{
18-
throw new NotSupportedException();
19-
}
20-
16+
public BSTMapNode() { }
2117
public BSTMapNode(TKey key) : this(key, default(TValue), 0, null, null, null) { }
2218
public BSTMapNode(TKey key, TValue value) : this(key, value, 0, null, null, null) { }
2319
public BSTMapNode(TKey key, TValue value, int subTreeSize, BSTMapNode<TKey, TValue> parent, BSTMapNode<TKey, TValue> left, BSTMapNode<TKey, TValue> right)

Diff for: DataStructures/Trees/IBinarySearchTree.cs

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ public interface IBinarySearchTree<T> where T : System.IComparable<T>
7878
/// <typeparam name="TValue">Type of records per node.</typeparam>
7979
public interface IBinarySearchTree<TKey, TValue> where TKey : System.IComparable<TKey>
8080
{
81+
BSTMapNode<TKey, TValue> Root { get; }
8182
int Count { get; }
8283
bool IsEmpty { get; }
8384
int Height { get; }

Diff for: DataStructures/Trees/RedBlackTreeMapNode.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public RedBlackTreeMapNode(TKey key, TValue value) : this(key, value, 0, null, n
1515
public RedBlackTreeMapNode(TKey key, TValue value, int height, RedBlackTreeMapNode<TKey, TValue> parent, RedBlackTreeMapNode<TKey, TValue> left, RedBlackTreeMapNode<TKey, TValue> right)
1616
{
1717
Key = key;
18-
Value = Value;
18+
Value = value;
1919
Color = RedBlackTreeColors.Red;
2020
Parent = parent;
2121
LeftChild = left;

Diff for: DataStructures/Trees/TreeDrawer.cs

+108-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ public static string DrawTree<T>(this IBinarySearchTree<T> tree) where T : IComp
2020
return String.Join("\n", _recursivelyDrawTree(tree.Root, out position, out width));
2121
}
2222

23+
public static string DrawTree<TKey, TValue>(this IBinarySearchTree<TKey, TValue> tree, bool includeValues = false) where TKey : IComparable<TKey>
24+
{
25+
int position, width;
26+
return String.Join("\n", _recursivelyDrawTree(tree.Root, out position, out width, includeValues));
27+
}
28+
2329

2430
/// <summary>
2531
/// /// Recusively draws the tree starting from node.
@@ -36,7 +42,9 @@ public static string DrawTree<T>(this IBinarySearchTree<T> tree) where T : IComp
3642
/// <param name="positionOutput"></param>
3743
/// <param name="widthOutput"></param>
3844
/// <returns>List of tree levels as strings.</returns>
39-
private static List<string> _recursivelyDrawTree<T>(BSTNode<T> node, out int positionOutput, out int widthOutput) where T : IComparable<T>
45+
private static List<string> _recursivelyDrawTree<T>
46+
(BSTNode<T> node, out int positionOutput, out int widthOutput)
47+
where T : IComparable<T>
4048
{
4149
widthOutput = 0;
4250
positionOutput = 0;
@@ -121,5 +129,104 @@ private static List<string> _recursivelyDrawTree<T>(BSTNode<T> node, out int pos
121129
positionOutput = position_out;
122130
return listOfLines;
123131
}
132+
133+
134+
private static List<string> _recursivelyDrawTree<TKey, TValue>
135+
(BSTMapNode<TKey, TValue> node, out int positionOutput, out int widthOutput, bool includeValues = false)
136+
where TKey : IComparable<TKey>
137+
{
138+
widthOutput = 0;
139+
positionOutput = 0;
140+
List<string> listOfLines = new List<string>();
141+
142+
if (node == null)
143+
{
144+
return listOfLines;
145+
}
146+
147+
//
148+
// Variables
149+
string nodeLabel = "";
150+
int padValue = 0;
151+
152+
List<string> leftLines, rightLines;
153+
leftLines = rightLines = new List<string>();
154+
155+
int leftPosition = 0, rightPosition = 0;
156+
int leftWidth = 0, rightWidth = 0;
157+
int middle, position_out, width_out;
158+
159+
//
160+
// Start drawing
161+
if (includeValues == true)
162+
{
163+
nodeLabel = String.Format("<{0}: {1}>", Convert.ToString(node.Key), Convert.ToString(node.Value));
164+
padValue = 4;
165+
}
166+
else
167+
{
168+
nodeLabel = Convert.ToString(node.Key);
169+
padValue = 2;
170+
}
171+
172+
// Visit the left child
173+
leftLines = _recursivelyDrawTree(node.LeftChild, out leftPosition, out leftWidth, includeValues);
174+
175+
// Visit the right child
176+
rightLines = _recursivelyDrawTree(node.RightChild, out rightPosition, out rightWidth, includeValues);
177+
178+
// Calculate pads
179+
middle = Math.Max(Math.Max(padValue, nodeLabel.Length), (rightPosition + leftWidth - leftPosition + 1));
180+
position_out = leftPosition + middle;
181+
width_out = leftPosition + middle + rightWidth - rightPosition;
182+
183+
while (leftLines.Count < rightLines.Count)
184+
leftLines.Add(new String(' ', leftWidth));
185+
186+
while (rightLines.Count < leftLines.Count)
187+
rightLines.Add(new String(' ', rightWidth));
188+
189+
if ((middle - nodeLabel.Length % padValue == 1) && (nodeLabel.Length < middle) && (node.Parent != null && node.IsLeftChild))
190+
nodeLabel += ".";
191+
192+
// Format the node's label
193+
nodeLabel = nodeLabel.PadCenter(middle, '.');
194+
195+
var nodeLabelChars = nodeLabel.ToCharArray();
196+
197+
if (nodeLabelChars[0] == '.')
198+
nodeLabelChars[0] = ' ';
199+
200+
if (nodeLabelChars[nodeLabelChars.Length - 1] == '.')
201+
nodeLabelChars[nodeLabelChars.Length - 1] = ' ';
202+
203+
nodeLabel = String.Join("", nodeLabelChars);
204+
205+
//
206+
// Construct the list of lines.
207+
listOfLines = new List<string>()
208+
{
209+
// 0
210+
(new String(' ', leftPosition )) + nodeLabel + (new String(' ', (rightWidth - rightPosition))),
211+
212+
// 1
213+
(new String(' ', leftPosition)) + "/" + (new String(' ', (middle - padValue))) + "\\" + (new String(' ', (rightWidth - rightPosition)))
214+
};
215+
216+
//
217+
// Add the right lines and left lines to the final list of lines.
218+
listOfLines =
219+
listOfLines.Concat(
220+
leftLines.Zip(
221+
rightLines, (left_line, right_line) =>
222+
left_line + (new String(' ', (width_out - leftWidth - rightWidth))) + right_line)
223+
).ToList();
224+
225+
//
226+
// Return
227+
widthOutput = width_out;
228+
positionOutput = position_out;
229+
return listOfLines;
230+
}
124231
}
125232
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Collections.Generic;
4+
5+
using DataStructures.Common;
6+
using DataStructures.Trees;
7+
8+
namespace C_Sharp_Algorithms.DataStructuresTests
9+
{
10+
public static class BinarySearchTreeMapTests
11+
{
12+
public static void DoTest()
13+
{
14+
// Binary Search Tree Map collection
15+
var bstMap = new BinarySearchTreeMap<int, string>(allowDuplicates: false);
16+
17+
// Testing data
18+
KeyValuePair<int, string>[] values = new KeyValuePair<int, string>[10];
19+
20+
// Prepare the values array
21+
for(int i = 1; i <= 10; ++i)
22+
{
23+
var keyValPair = new KeyValuePair<int, string>(i, String.Format("Integer: {0}", i));
24+
values[i - 1] = keyValPair;
25+
}
26+
27+
28+
//
29+
// Test singular insert
30+
for (int i = 0; i < 10; ++i)
31+
bstMap.Insert(values[i].Key, values[i].Value);
32+
33+
Debug.Assert(bstMap.Count == values.Length, "Expected the same number of items.");
34+
35+
bstMap.Clear();
36+
37+
38+
//
39+
// Test collection insert
40+
bstMap.Insert(values);
41+
42+
43+
//
44+
// Test enumeration of key-value pairs is still in oreder
45+
var enumerator = bstMap.GetInOrderEnumerator();
46+
for (int i = 0; i < 10; ++i)
47+
{
48+
if (enumerator.MoveNext())
49+
{
50+
var curr = enumerator.Current;
51+
if (curr.Key != values[i].Key || curr.Value != values[i].Value)
52+
throw new Exception();
53+
}
54+
}
55+
56+
57+
//
58+
// Test against re-shuffled insertions (not like above order)
59+
bstMap = new BinarySearchTreeMap<int, string>(allowDuplicates: false);
60+
61+
bstMap.Insert(4, "int4");
62+
bstMap.Insert(5, "int5");
63+
bstMap.Insert(7, "int7");
64+
bstMap.Insert(2, "int2");
65+
bstMap.Insert(1, "int1");
66+
bstMap.Insert(3, "int3");
67+
bstMap.Insert(6, "int6");
68+
bstMap.Insert(0, "int0");
69+
bstMap.Insert(8, "int8");
70+
bstMap.Insert(10, "int10");
71+
bstMap.Insert(9, "int9");
72+
73+
Debug.Assert(bstMap.Count == values.Length, "Expected the same number of items.");
74+
75+
76+
//
77+
// ASSERT INSERTING DUPLICATES WOULD BREAK
78+
var insert_duplicate_passed = true;
79+
try
80+
{
81+
// 2 already exists in tree
82+
bstMap.Insert(2, "int2");
83+
insert_duplicate_passed = true;
84+
}
85+
catch
86+
{
87+
insert_duplicate_passed = false;
88+
}
89+
90+
Debug.Assert(insert_duplicate_passed == false, "Fail! The tree doesn't allow duplicates");
91+
92+
93+
//
94+
// Test find
95+
Debug.Assert(bstMap.Find(5).Key == 5, "Wrong find result!");
96+
Debug.Assert(bstMap.FindMin().Key == 0, "Wrong min!");
97+
Debug.Assert(bstMap.FindMax().Key == 10, "Wrong max!");
98+
99+
100+
//
101+
// Assert find raises exception on non-existing elements
102+
bool threwKeyNotFoundError = false;
103+
104+
try
105+
{
106+
bstMap.Find(999999999);
107+
threwKeyNotFoundError = false;
108+
}
109+
catch(KeyNotFoundException)
110+
{
111+
threwKeyNotFoundError = true;
112+
}
113+
114+
Debug.Assert(true == threwKeyNotFoundError, "Expected to catch KeyNotFoundException.");
115+
116+
117+
//
118+
// PRINT TREE
119+
Console.WriteLine("*****************************");
120+
Console.WriteLine(" [*] BINARY SEARCH TREE TREE:\r\n");
121+
Console.WriteLine("*****************************");
122+
Console.WriteLine(bstMap.DrawTree());
123+
Console.WriteLine("\r\n");
124+
125+
126+
//
127+
// Assert count
128+
Debug.Assert(bstMap.Count == 11);
129+
130+
131+
//
132+
// Assert existence and nonexistence of some items
133+
Debug.Assert(bstMap.Contains(1) == true);
134+
Debug.Assert(bstMap.Contains(3) == true);
135+
Debug.Assert(bstMap.Contains(999) == false);
136+
137+
138+
//
139+
// Do some deletions
140+
bstMap.Remove(7);
141+
bstMap.Remove(1);
142+
bstMap.Remove(3);
143+
144+
145+
//
146+
// Assert count
147+
Debug.Assert(bstMap.Count == 8);
148+
149+
150+
//
151+
// Assert nonexistence of previously existing items
152+
Debug.Assert(bstMap.Contains(1) == false);
153+
Debug.Assert(bstMap.Contains(3) == false);
154+
155+
156+
//
157+
// Remove root key
158+
var oldRootKey = bstMap.Root.Key;
159+
bstMap.Remove(bstMap.Root.Key);
160+
161+
162+
//
163+
// Assert count
164+
Debug.Assert(bstMap.Count == 7);
165+
166+
167+
//
168+
// Assert nonexistence of old root's key
169+
Debug.Assert(bstMap.Contains(oldRootKey) == false);
170+
171+
172+
//
173+
// PRINT TREE
174+
Console.WriteLine("*****************************");
175+
Console.WriteLine(" [*] BINARY SEARCH TREE TREE:\r\n");
176+
Console.WriteLine("*****************************");
177+
Console.WriteLine(bstMap.DrawTree(includeValues: true));
178+
Console.WriteLine("\r\n");
179+
180+
Console.ReadLine();
181+
}//end-do-test
182+
}
183+
}
184+

0 commit comments

Comments
 (0)