-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbst.cpp
More file actions
447 lines (429 loc) · 12.4 KB
/
bst.cpp
File metadata and controls
447 lines (429 loc) · 12.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
/******************************************************************************
Name: bst.cpp
Des: This file contains the implementation for the binary search tree abstract
data type.
Author: Matthew Thompson
Date: 4/25/2017
******************************************************************************/
#include"bst.h"
#include<iostream>
#include<fstream>
/******************************************************************************
Name: Tree (Constructor)
Des: This function constructs a binary search tree ADT. It simply sets the
root of the tree to nullptr to indicate an empty tree.
******************************************************************************/
Tree::Tree()
{
root = nullptr;
}
/******************************************************************************
Name: ~Tree (Destructor)
Des: This function destructs a dynamically allocated binary search tree by
performing a postorder traversal. Once a node is visited, it is passed to the
deleteNode function where it should be deleted properly. With a postorder
traversal, each node visited should be a leaf node. This function will give
back the dynamically allocated memory to the heap once the tree goes out of
scope.
******************************************************************************/
Tree::~Tree()
{
Node * currentNode;
while (root != nullptr)
{
currentNode = root;
while (currentNode->left != nullptr)
{
currentNode = currentNode->left;
}
while (currentNode->right != nullptr)
{
currentNode = currentNode->right;
}
deleteNode(currentNode);
}
}
/******************************************************************************
Name: insert
Des: This function attempts to create a new node and insert it into the tree.
If dynamic memory allocation fails, this function returns false. Otherwise, the
function returns true. The function uses the information passed from criminal.cpp
to fill the node, and it inserts the node at the proper location in the binary
search tree using the sort function.
******************************************************************************/
bool Tree::insert(TreeType name, TreeType attributes[8], int attributeCount)
{
Node * newNode = new Node;
// If dynamic memory allocation fails.
if (newNode == nullptr)
{
return false;
}
else
{
// Add the information passed from criminal.cpp to the new node.
newNode->name = name;
for (int i = 0; i < 8; i++)
{
newNode->attributes[i] = attributes[i];
}
newNode->attributeCount = attributeCount;
newNode->left = nullptr;
newNode->right = nullptr;
}
Node * currentNode = root;
// If the tree is empty, the new node becomes the root node.
if (currentNode == nullptr)
{
root = newNode;
newNode->parent = nullptr;
}
else
{
// Assign the node to the proper location in the binary search tree.
sort(currentNode, newNode);
}
return true;
}
/******************************************************************************
Name: searchAndPrune
Des: This public function calls the private and recursive function
postorderTraversalAndPrune. This function is needed to pass the root node to
the function initially because the criminal.cpp file has no access to the
private root of the tree. This function will cause any nodes not containing
the attribute to be pruned from the tree.
******************************************************************************/
void Tree::searchAndPrune(TreeType attribute)
{
Node * currentNode = root;
postorderTraversalAndPrune(currentNode, attribute);
}
/******************************************************************************
Name: postorderTraversalAndPrune
Des: This recursive function performs a postorder traversal on the binary
search tree to find nodes which do not contain the attribute passed to the
function. If the node lacks the requested attribute, the node is passed to
deleteNode to be deleted.
******************************************************************************/
void Tree::postorderTraversalAndPrune(Node * currentNode, TreeType attribute)
{
// If the tree is not empty...
if (currentNode != nullptr)
{
if (currentNode->left != nullptr)
{
postorderTraversalAndPrune(currentNode->left, attribute);
}
if (currentNode->right != nullptr)
{
postorderTraversalAndPrune(currentNode->right, attribute);
}
bool nodeHasAttribute = false;
// Search for the requested attribute in the current node.
for (int i = 0; i < currentNode->attributeCount; i++)
{
if (currentNode->attributes[i] == attribute)
{
nodeHasAttribute = true;
}
}
if (!nodeHasAttribute)
{
deleteNode(currentNode);
}
}
}
/******************************************************************************
Name: deleteNode
Des: This function takes a node and decides which delete function to assign the
node to. The three cases (leaf, one-child, two-child) are each deleted
differently, so proper distinction and function selection and crucial for the
success of the program. If the tree is empty, this function returns false.
******************************************************************************/
bool Tree::deleteNode(Node * currentNode)
{
// If the tree is empty, return false.
if (root == nullptr)
{
return false;
}
else
{
// Leaf case
if (currentNode->left == nullptr && currentNode->right == nullptr)
{
deleteLeafNode(currentNode);
}
// Two-child case
else if (currentNode->left != nullptr && currentNode->right != nullptr)
{
deleteTwoChildNode(currentNode);
}
// One-child case
else
{
deleteOneChildNode(currentNode);
}
return true;
}
}
/******************************************************************************
Name: deleteLeafNode
Des: This function takes a leaf node and removes it from the tree. It sets
the leaf's parent's pointer to the leaf to null and then deletes the leaf node.
******************************************************************************/
void Tree::deleteLeafNode(Node * currentNode)
{
// If the leaf node is the root:
if (currentNode->parent == nullptr)
{
root = nullptr;
}
else
{
// If the leaf is a left child of its parent.
if (currentNode->parent->left == currentNode)
{
currentNode->parent->left = nullptr;
}
// If the leaf is a right child of its parent.
else
{
currentNode->parent->right = nullptr;
}
}
delete currentNode;
}
/******************************************************************************
Name: deleteOneChildNode
Des: This function takes a node with only one child and prunes it from the tree.
It properly reassigns the parent left or right pointers pointing to the current
node to the node's one child and connects the one child's parent pointer to
the current node's parent.
******************************************************************************/
void Tree::deleteOneChildNode(Node * currentNode)
{
// If the current node is the root.
if (currentNode->parent == nullptr)
{
if (currentNode->left != nullptr)
{
currentNode->left->parent = nullptr;
root = currentNode->left;
}
else
{
currentNode->right->parent = nullptr;
root = currentNode->right;
}
}
else
{
// If the one child is the left child.
if (currentNode->left != nullptr)
{
currentNode->left->parent = currentNode->parent;
if (currentNode->left->name > currentNode->parent->name)
{
currentNode->parent->right = currentNode->left;
}
else
{
currentNode->parent->left = currentNode->left;
}
}
// If the one child is the right child.
else
{
currentNode->right->parent = currentNode->parent;
if (currentNode->right->name > currentNode->parent->name)
{
currentNode->parent->right = currentNode->right;
}
else
{
currentNode->parent->left = currentNode->right;
}
}
}
delete currentNode;
}
/******************************************************************************
Name: deleteTwoChildNode
Des: This function takes a node with two children and properly prunes it from
the tree. The algorithm finds the closest predecessor to the current node,
replaces the current node's values with those of the closest predecessor's, and
then deletes the node that is the original closest predecessor.
******************************************************************************/
void Tree::deleteTwoChildNode(Node * currentNode)
{
// Find closest predecessor node.
Node * closestPredecessor = currentNode;
closestPredecessor = closestPredecessor->left;
while (closestPredecessor->right != nullptr)
{
closestPredecessor = closestPredecessor->right;
}
// Replace the data in the two child node with the data from the predecessor node.
currentNode->name = closestPredecessor->name;
for (int i = 0; i < 8; i++)
{
currentNode->attributes[i] = closestPredecessor->attributes[i];
}
currentNode->attributeCount = closestPredecessor->attributeCount;
deleteNode(closestPredecessor);
}
/******************************************************************************
Name: output
Des: This function calls the recursive private function inOrderTraversalAndOutput
which performs and in-order traversal and outputs the nodes individually. This
function is required to pass the root into the function from a public function
that is in the tree class. Criminal.cpp has no access to the root of the tree.
******************************************************************************/
void Tree::output(ofstream& fout)
{
Node * currentNode = root;
inOrderTraversalAndOutput(currentNode, fout);
}
/******************************************************************************
Name: inOrderTraversalAndOutput
Des: This function performs an in-order traversal of the binary tree and
outputs the node's name field on each process step. This outputs to the file
output stream at criminal.out.
******************************************************************************/
void Tree::inOrderTraversalAndOutput(Node * currentNode, ofstream& fout)
{
// If the tree is empty, there were no criminals who had an attribute that
// matched the request.
if (root == nullptr)
{
fout << "NO SUSPECTS FOR THIS CASE" << endl;
}
else if(currentNode != nullptr)
{
inOrderTraversalAndOutput(currentNode->left, fout);
fout << currentNode->name << endl;
inOrderTraversalAndOutput(currentNode->right, fout);
}
}
/******************************************************************************
Name: sort
Des: This function uses the new node's name and properly sorts the new node
into the tree alphabetically. If the new node comes before the current node
alphabetically, it proceeds to the current node's left child and reevaluates.
If there is no child to go to, the traversal stops and the node is inserted
into the tree at this place.
******************************************************************************/
void Tree::sort(Node * currentNode, Node * newNode)
{
if (newNode->name > currentNode->name)
{
if (currentNode->right != nullptr)
{
sort(currentNode->right, newNode);
}
else
{
currentNode->right = newNode;
newNode->parent = currentNode;
}
}
else
{
if (currentNode->left != nullptr)
{
sort(currentNode->left, newNode);
}
else
{
currentNode->left = newNode;
newNode->parent = currentNode;
}
}
}
Node * Tree::find(string key)
{
if (root == nullptr)
{
return nullptr;
}
else
{
Node * currentNode = root;
while (currentNode != nullptr)
{
if (key == currentNode->name)
{
return currentNode;
}
else
{
if (key < currentNode->name)
{
currentNode = currentNode->left;
}
else
{
currentNode = currentNode->right;
}
}
}
// If nothing was found
return nullptr;
}
}
bool Tree::insert(string key)
{
Node * newNode = new Node;
if (newNode == nullptr)
{
return false;
}
else
{
newNode->name = key;
newNode->left = nullptr;
newNode->right = nullptr;
Node * currentNode = root;
bool nodeInserted = false;
while (nodeInserted != true)
{
if (root == nullptr)
{
root = newNode;
newNode->parent = nullptr;
nodeInserted = true;
}
else
{
if (key < currentNode->name)
{
if (currentNode->left == nullptr)
{
currentNode->left = newNode;
newNode->parent = currentNode;
nodeInserted = true;
}
else
{
currentNode = currentNode->left;
}
}
else
{
if (currentNode->right == nullptr)
{
currentNode->right = newNode;
newNode->parent = currentNode;
nodeInserted = true;
}
else
{
currentNode = currentNode->right;
}
}
}
}
return true;
}
}