Skip to content

Commit 0542012

Browse files
authored
Bst node deletion and test cases
1 parent 3af5282 commit 0542012

File tree

1 file changed

+221
-0
lines changed

1 file changed

+221
-0
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
//----------------------------------------
2+
// Binary search tree
3+
// Topics covered:
4+
// - node deletion
5+
// - the tree should remain a bst after the deletion
6+
// - pretty print that will show the tree structure
7+
8+
#include <iostream>
9+
#include <vector>
10+
#include <memory> // unique_ptr
11+
using namespace std;
12+
13+
struct Node
14+
{
15+
int data;
16+
Node* left;
17+
Node* right;
18+
};
19+
20+
Node* Create(int value)
21+
{
22+
return new Node{value, nullptr, nullptr};
23+
}
24+
25+
// fwd declarations
26+
void TestCreation(const vector<int> & input);
27+
void TestDeletion(const vector<int> & input, const vector<int> & keysToDelete);
28+
Node* rCreate(const vector<int> & input);
29+
Node* rInsert(Node* root, int value);
30+
bool IsLeaf(const Node* current);
31+
Node* LeftMost(Node* current);
32+
void PrettyDfs(Node* root, int depth = 0, const char* name = "");
33+
// end fwd declarations
34+
35+
/* bst node deletion cases to handle:
36+
if the deleted node:
37+
- is a leaf, nothing to do
38+
- has one child, the child will take it's place
39+
- has two children, find the inorder successor of the deleted node that will take it's place
40+
- the inorder successor will be the smallest element inside the right sub-tree
41+
*/
42+
43+
// this is the main deletion code
44+
Node* DeleteNode(Node* root, int key)
45+
{
46+
if (root == nullptr)
47+
return nullptr;
48+
49+
if (key < root->data)
50+
{
51+
root->left = DeleteNode(root->left, key);
52+
return root;
53+
}
54+
else if (key > root->data)
55+
{
56+
root->right = DeleteNode(root->right, key);
57+
return root;
58+
}
59+
else
60+
{
61+
// root is being deleted, handle all cases listed above
62+
63+
if (IsLeaf(root))
64+
{
65+
unique_ptr<Node> deleteRootAfterExit(root);
66+
return nullptr;
67+
}
68+
else if (root->left == nullptr)
69+
{
70+
unique_ptr<Node> deleteRootAfterExit(root);
71+
return root->right;
72+
}
73+
else if (root->right == nullptr)
74+
{
75+
unique_ptr<Node> deleteRootAfterExit(root);
76+
return root->left;
77+
}
78+
else
79+
{
80+
auto successor = LeftMost(root->right);
81+
root->data = successor->data;
82+
root->right = DeleteNode(root->right, successor->data);
83+
84+
return root;
85+
}
86+
}
87+
}
88+
89+
int main(int argc, char *argv[])
90+
{
91+
{
92+
/*
93+
3
94+
/ \
95+
1 5
96+
\ /
97+
2 4
98+
99+
*/
100+
101+
const vector<int> input{3, 1, 2, 5, 4};
102+
TestCreation(input);
103+
104+
// the delete test case will cover all cases:
105+
// leaf node, node with one child and node with two children (root of the tree)
106+
const vector<int> keysToDelete{4, 1, 3};
107+
TestDeletion(input, keysToDelete);
108+
}
109+
110+
return 0;
111+
}
112+
113+
void TestCreation(const vector<int> & input)
114+
{
115+
{
116+
auto root = rCreate(input);
117+
118+
cout << "Printing bst created using recursion" << endl;
119+
PrettyDfs(root, 0, "root");
120+
}
121+
}
122+
123+
void TestDeletion(const vector<int> & input, const vector<int> & keysToDelete)
124+
{
125+
auto root = rCreate(input);
126+
127+
for (auto key : keysToDelete)
128+
{
129+
root = DeleteNode(root, key);
130+
cout << endl << "Printing tree after deleting key " << key << endl;
131+
PrettyDfs(root, 0, "root");
132+
}
133+
}
134+
135+
// wrapper function to create bst from a list of keys
136+
Node* rCreate(const vector<int> & input)
137+
{
138+
Node* root = nullptr;
139+
for (auto value : input)
140+
root = rInsert(root, value);
141+
142+
return root;
143+
}
144+
145+
// recursive insert function for bst
146+
Node* rInsert(Node* root, int value)
147+
{
148+
if (root == nullptr)
149+
return Create(value);
150+
151+
if (value < root->data)
152+
{
153+
root->left = rInsert(root->left, value);
154+
}
155+
else if (value > root->data)
156+
{
157+
root->right = rInsert(root->right, value);
158+
}
159+
else
160+
{
161+
// ignore dupe values; an alternate solution is to have a ref count
162+
// inside every node and increment it when we get a dupe value
163+
}
164+
165+
return root;
166+
}
167+
168+
bool IsLeaf(const Node* current)
169+
{
170+
return !(current->left || current->right);
171+
}
172+
173+
Node* LeftMost(Node* current)
174+
{
175+
while (current && current->left)
176+
current = current->left;
177+
178+
return current;
179+
}
180+
181+
void PrettyDfs(Node* root, int depth, const char* name)
182+
{
183+
if (root)
184+
{
185+
for (int counter = 0; counter < depth; ++counter)
186+
{
187+
cout << " |";
188+
}
189+
190+
cout << "-->" << root->data << "(" << name << ")" << endl;
191+
192+
PrettyDfs(root->left, depth + 1, "L");
193+
PrettyDfs(root->right, depth + 1, "R");
194+
}
195+
}
196+
197+
/*
198+
Output:
199+
Printing bst created using recursion
200+
-->3(root)
201+
|-->1(L)
202+
| |-->2(R)
203+
|-->5(R)
204+
| |-->4(L)
205+
206+
Printing tree after deleting key 4
207+
-->3(root)
208+
|-->1(L)
209+
| |-->2(R)
210+
|-->5(R)
211+
212+
Printing tree after deleting key 1
213+
-->3(root)
214+
|-->2(L)
215+
|-->5(R)
216+
217+
Printing tree after deleting key 3
218+
-->5(root)
219+
|-->2(L)
220+
221+
*/

0 commit comments

Comments
 (0)