Making a delete function for a binary search tree in C++ - c++

Edited*: I'm working on the delete function for a binary search tree. I'm just working on the first case right now. I think this is correct, but I'm wondering if it can be done recursively, or more efficiently. Any help is appreciated. Assume BSTSearch searches for a node, isLeaf returns true if the node is a leaf, and each node has a pointer that allows them access to their parent.
void
BinarySearchTree::BSTDelete(int x, BSTNode *node){
BSTNode *deleteNode;
deleteNode = BSTSearch(x,node);
if(isLeaf(deleteNode)){
if(deleteNode->sortkey > (deleteNode->parent)->sortkey){
delete (deleteNode->parent)->right;
(deleteNode->parent)->right = NULL;
}
else{
delete (deleteNode->parent)->left;
(deleteNode->parent)->left = NULL;
}
}

You don't need a pointer to the parent. Here is a recursive version that should work: (pass by reference (&), in case you don't know, allows you to modify the variable, similar to pass by pointer; BSTNode *& is a pointer passed by reference, so we can modify the value of node->left/right (pointers) (not just what they're pointing to))
void BinarySearchTree::BSTDelete(int x, BSTNode *&node)
{
if (node == NULL)
return;
if (x == node->sortKey)
{
if (isLeaf(node))
{
delete node;
node = NULL;
}
else
{
// other stuff goes here
}
return;
}
else if (x < node->sortKey)
BSTDelete(x, node->left);
else
BSTDelete(x, node->right);
}

Related

c++ reference type as recursive function parameter

Node * BST::insert_real(int key, Node *& node)
{
if (node == nullptr)
return node = new Node(key);
if (key < node->key)
return insert_real(key, node->left);
else if (key > node->key)
return insert_real(key, node->right);
else
return nullptr;
}
Node * BST::insert(int key)
{
return insert_real(key, header->left);
}
BinarySearchTree, the insert function.
If the key always goes left, when the function insert_all() runs to the position node = new Node(key) , whether the node is equivalent to header->left->left->left->left->left->......->left->left?
if my guess above is right, the code header->left->left->left->left->left->......->left->left will bring some burden.(if so, i will replace Node*& with Node**)
The words I say above is right?
If the key always goes left, when the function insert_all() runs to the position node = new Node(key) , whether the node is equivalent to header->left->left->left->left->left->......->left->left
No, in the below call you are not changing node parameter which you received.You are just calling insert_real() with some other parameter.
return insert_real(key, node->left);
The only time you change node is below
if (node == nullptr)
return node = new Node(key);

C++ Binary Search Tree Insertion functions

Helly everyone,
I took a C++ coding course with practically no prior knowledge(my understanding of pointers is still somewhat shakey)at University this semester.
I have to implement a binary search tree in C++ and my problem is as follows:
Over a predefined Node structure with values and pointers to a left and a right node I am supposed to implement several functions, two of them being:
void InsertNode(Node* root, Node* node)
which is supposed to fit the handed node into the given tree "root",
and another one called
void InsertValue(Node* root, int value)
which should create a new instance of the node struct with the passed value and fit it in the given tree "root". To do so I am supposed to use both CreateNode (simple function to create Node* pointer of a new Node instance with int value and left/right pointers set to NULL) and InsertNode.
Im kind of running in a treadmill here and i dont think i really understand how the functions are supposed to work(eg. the difference between them).
Yesterday i wrote this function:
void InsertNode(Node* root, Node* node){
if(root == NULL){
root = CreateNode(node->value);
}
else if(root->value < node->value){
if(node->left != NULL){
InsertNode(root, node->left);
}
else{
node->left = CreateNode(root->value);
}
}
else if(root->value > node->value){
if(node->right != NULL){
InsertNode(root, node->right);
}
else{
node->right = CreateNode(root->value);
}
}
}
Since im not really able to test these functions without the later functions that will actually build the tree with given nodes i was curious if i could get some help here with the next functions InsertValue(what is it supposed to do that InsertNode doesnt do already? :S)
Greetings and thanks in advance.
Initial note: This answer assumes that the InsertNode function is initially called with root being the root of the tree, and node being the node to insert into the tree.
One problem is this statement:
root = CreateNode(node->value);
Since the argument root is passed by value, which means that it is copied, the assignment will only change the local copy. Once the function returns the original pointer that you pass to the function will not have changed.
You need to pass the pointer by reference, meaning the root argument references the original variable passed in to the function, instead of it being copied. You do this by using an ampersand when declaring the argument:
Node*& root
The above means that root is a reference to a pointer to Node.
So the complete InsertNode declaration should look like
void InsertNode(Node*& root, Node* node)
There are also other problems, for example these lines are not correct:
if(node->left != NULL){
InsertNode(root, node->left);
}
else{
node->left = CreateNode(root->value);
}
This is not correct because node->left should be NULL always, which makes you create a new node using the value from the root of the tree, and assign it to node->left, but you never insert node in the tree.
What you should instead do is simply
InsertNode(node->left, node);
Of course you should do the same change for setting the right branch.
Combining the two solutions above, your function would look like
void InsertNode(Node*& root, Node* node)
{
if (root == 0)
root = node;
else if (root->value < node->value)
InsertNode(root->left, node);
else
InsertNode(root->right, node);
}
This function also solves a third problem with your current code: What if node->value is equal to root->value? The above function puts it in the right branch.
When you are creating a tree, value are also assigned with each node. See following code:
typedef struct BST {
int data;
struct BST *lchild, *rchild;
} node;
void insert(node *root, node *new_node) {
if (new_node->data < root->data) {
if (root->lchild == NULL)
root->lchild = new_node;
else
insert(root->lchild, new_node);
}
if (new_node->data > root->data) {
if (root->rchild == NULL)
root->rchild = new_node;
else
insert(root->rchild, new_node);
}
}
node *new_node, *root;
int main()
{
new_node = get_node();
printf("\nEnter The Element ");
scanf("%d", &new_node->data);
if (root == NULL) /* Tree is not Created */
root = new_node;
else
insert(root, new_node)
}
The below code is in Python and is used for insertion in a BST ::
class Node :
def __init__(self.key):
self.left = None
self.right = None
self.val = key
def insert(root.node):
if root is None :
root = node
else :
if root.val < node.val:
if root.right is None :
root.right = node
else :
insert(root.right, node)
else :
if root.left is None :
root.left = node
else :
insert(root.left, node)
def inorder(root):
if root :
inorder(root.left)
print(root.val)
inorder(root.right)
# Driver program to test the above functions
# Let us create the following BST
# 50
# / \
# 30 70
# / \ / \
# 20 40 60 80
r = Node(50)
insert(r,Node(30))
insert(r,Node(20))
insert(r,Node(40))
insert(r,Node(70))
insert(r,Node(60))
insert(r,Node(80))
# Print inoder traversal of the BST
inorder(r)

Deleting Root Node of a Binary Search Tree

I have this function for deleting a node in a binary search tree which seems to be working EXCEPT in the case where I ask it to delete the root node. It is supposed to take the right-most value on the left and replace the node with that; however, once that happens, the new root node's children pointers don't seem to point to the original root node's children. Code is as follows:
bool delete_node(Node*& root, TYPE data) {
Node* toDelete;
Node* parent;
// This function is defined appropriately elsewhere, and finds the target to be deleted
toDelete = find(data, root);
if (!toDelete) {
return false;
}
// This function is defined appropriately elsewhere, and finds the parent of the node to be deleted
parent = find_parent(root, toDelete);
// Other cases left out because they work
// If the target node has two children:
if (toDelete->left && toDelete->right)
{
// find rightmost child on left that is a leaf
Node *replacement = toDelete->left;
while (replacement->right)
{
replacement = replacement->right;
}
// set the target node's data
toDelete->data = replacement->data;
if (parent)
{
if ( parent->data < toDelete->data )
{
parent->right = replacement;
} else
{
parent->left = replacement;
}
} else
{
// if node has no parents, then it is the root and should be replaced with replacement
// This line here is what seems to be causing my trouble...I think
root = replacement;
}
parent = find_parent(toDelete, replacement);
if (parent)
{
if (parent->left == replacement)
parent->left = NULL;
else
parent->right = NULL;
}
delete toDelete;
return true;
}
}
Thanks in advance!
what I ended coming up with was this: keep track of the parent node that is one above the node that replaces the node to be deleted. there will then be 2 cases to consider: the parent is the node to be deleted and parent is not the node to be deleted. by replacing the appropriate parts of the tree at the right case, the structure and invariants of the tree remained ok and the node to be deleted was successfully deleted. technically, it would be the data at the node to be deleted.
else if (toDelete->left != NULL && toDelete->right != NULL) {
// find rightmost child on left that is a leaf
Node* replacement = toDelete->left;
parent = toDelete;
// parent is now the parent of the replacement
while ( replacement->right ) {
parent = replacement;
replacement = replacement->right;
} // By the end, parent will be the node one above replacement
toDelete->key = replacement->key;
if (parent == target)
parent->left = replacement->left;
else
parent->right = replacement->left;
delete replacement;
return true;
}
This is what I did to make it work. Just check if the node is the root node, and if so, set the new root. Below is the working code I have. The three places marked by asterisks is what I added to make it work. All the other lines of code is just standard textbook theory.
inline NamesBinaryTree::Node* NamesBinaryTree::Node::removeNode (Node*& node, const Female* female, stringComparisonFunction s) { // Taken from p.253 of Alex Allain's "Jumping Into C++".
if (!node)
return nullptr;
if (node->femaleInfo.first == female->getName()) {
if (!node->left) { // i.e. node has either one child or zero children.
Node* rightNode = node->right;
if (node->isRoot()) // ***
namesBinaryTree.setRoot(rightNode); // Tested to work correctly. Note that we cannot call 'delete node;', since that will delete the very root that we are setting!
else
delete node;
return rightNode; // This will return nullptr if node->right is also nullptr, which is what we would want to do anyway since that would mean that node has zero children.
}
if (!node->right) { // i.e. node has exactly one child, namely its left child, in which case return that left child.
Node* leftNode = node->left;
if (node->isRoot()) // ***
namesBinaryTree.setRoot(leftNode);
else
delete node;
return leftNode; // This will never be nullptr, else the previous if condition would have been met instead.
}
Node* maxNode = findMaxNode(node->left); // node has two children, so it shall be replaced by the largest valued node in its left subtree.
maxNode->left = removeMaxNode(node->left, maxNode); // Note that maxNode->left = node->left is not enough because without actually removing maxNode, the node that was pointing to maxNode will now be pointing to maxNode in its new position (and the subtree under it), and the subtree that was under maxNode will now be gone.
maxNode->right = node->right;
if (node->isRoot()) // ***
namesBinaryTree.setRoot(maxNode); // Tested to work correctly.
else
delete node;
return maxNode;
}
else {
const int result = (*s)(female->getName(), node->femaleInfo.first);
if (result < 0)
node->left = removeNode(node->left, female, s); // This assignment can only work if node is passed by reference (hence the parameter Node*& node), at least this is what "C++ Essentials" did in their solution, p.247.
else // Don't use 'else if (result > 0)'. Let the equality case be covered here too (just as in NamesBinaryTree::Node::insertNode).
node->right = removeNode(node->right, female, s); // Again, this assignment can only work if node is passed by reference (hence the parameter Node*& node).
}
return node; // So if node->femaleInfo.first != female->getName(), then the same node is returned, which means that the two assignment lines above don't change any values.
}

Binary Tree findHeight

So I'm trying to add a findHeight method to my professors Binary Tree Class, and I'm having a bit of trouble.
BTNode<T> findParent(BTNode<T> Root, BTNode<T> child)
{
if(!root)
{
return Null;
}
if(Root.left* == child || Root.right* == child)
{
return Root;
}
else
{
//recursively checks left tree to see if child node is pointed to
findParent(Root.left, child);
//recursively checks right tree to see if child node is pointed to
findParent(Root.right, child);
}
int findHeight(BTNode<T> thisNode)
{
if (Count.findParent(.root, thisNode) == null)
{
return 0;
}
return findHeight(thisNode.findParent) + 1;
}
My problem is that in the findHeight method, it calls the findParent() method, and I have to reference the root of the binary tree that the parameter thisNode comes from, and because this is just part of the class, I don't know how I am supposed to reference the root. The BT (binary tree) class has a function that returns the root of the tree, but since I have no Binary Tree to reference, I don't know what to do. Please Help!!!
Normally, the findHeight function wouldn't "worry" about finding the root of the tree -- it just finds the height of the tree below whatever node it's passed. It usually looks something like this:
int findHeight(BTNode <T> *thiNode) {
if (thisNode == NULL)
return 0;
int left_height = findHeight(thisNode->left);
int right_height = findHeight(thisNode->right);
return 1 + max(left_height, right_height);
}
It's then up to the user to pass in the root of the tree whose height they want.

Interview Coding - Take a pointer to a Node structure as a parameter and return a complete copy of the passed-in data structure

This is an interview question that I found interesting.
Write a method that takes a pointer to a Node structure as a parameter and returns a complete copy of the passed-in data structure.
The Node structure contains two pointers to other Node structures.
For example, the method signature could look like so:
Node* Copy(Node* root);
Note - Do not make any assumptions about the data structure – it could be a tree, linked list, graph, etc.
How can this be done for any data structure ?
In the generic graph case, you need a mapping from nodes in the original graph to nodes in the new graph, so that when a cycle is encountered, the proper link gets created. If you happen to have extra temporary space in each node, large enough to hold a pointer, then you can store the mapping directly in the nodes; otherwise, you'll need to use an external map, such as an associative array or hash table.
Then it's just a matter of traversing the graph, copying nodes, and looking up the corresponding edges. Something like this:
struct Node
{
Node(int _data) : data(_data) { memset(links, 0, sizeof(links)); }
int data;
Node *links[2];
}
Node *Copy(Node *root)
{
typedef std::map<Node*, Node*> NodeMap;
NodeMap nodeMap;
std::deque<Node*> nodesToVisit;
// Set up initial new root and mapping for the root
Node *newRoot = new Node(root->data);
nodeMap[root] = newRoot;
// Breadth-first search the graph
nodesToVisit.push_back(root);
while(!nodesToVisit.empty())
{
Node *cur = nodesToVisit.front();
nodesToVisit.pop_front();
Node *newCur = nodeMap[cur];
for(int i = 0; i < 2; i++)
{
Node *link = cur->links[i];
if(link)
{
// If we've already created the corresponding node for this
// link, use that. Otherwise, create it and add it to the map.
NodeMap::iterator mappedLink = nodeMap.find(link);
if(mappedLink != nodeMap.end())
{
newCur->links[i] = mappedLink->second;
}
else
{
Node *newLink = new Node(link->data);
nodeMap[link] = newLink;
newCur->links[i] = newLink;
nodesToVisit.push_back(link);
}
}
}
}
return newRoot;
}
The problem as stated is impossible. You have to assume that the entire data structure is stored entirely within the content of nodes that are accessible from that initial one. But that is not an assumption you are allowed to make. Even your standard basic double linked list might not fit that description.
class Copier {
std::map <Node*, Node*> copies;
Node* Copy(Node* n) {
if (!n) return 0;
Node*& copy = copies[n];
if (!copy) {
copy = new Node();
copy.node1 = Copy(n.node1);
copy.node2 = Copy(n.node2);
}
return copy;
}
}
Node* Copy(Node* root) {
if (root == NULL)
return root;
std::unordered_map<Node*, Node*> completed;
std::deque<Node*> todo;
Node *ret = new Node(*scur);
completed.push_back(std::make_pair(root, ret));
todo.push_pack(root);
//while there's more nodes to duplicate
do {
//duplicate the node
Node* oldNode = todo.back();
Node* newNode = completed[cur];
todo.pop_back();
if(oldNode->left) {
auto iter = completed.find(oldNode->left);
//if it has a left child that needs duplicating, add it to the todo list
if (iter == completed.end()) {
newNode->left = new Node(*(oldNode->left));
completed.push_back(std::make_pair(oldNode->left, newNode->left));
todo.push_back(oldNode->left);
} else {
newNode->left = completed[oldNode->left];
}
}
if(oldNode->right) {
auto iter = completed.find(oldNode->right);
//if it has a right child that needs duplicating, add it to the todo list
if (iter == completed.end()) {
newNode->right = new Node(*(oldNode->right));
completed.push_back(std::make_pair(oldNode->right, newNode->right));
todo.push_back(oldNode->right);
} else {
newNode->right= completed[oldNode->right];
}
}
} while(todo.empty() == false)
//return the translation of the root
return ret;
}
Doesn't have stack overflow, root can be NULL, doesn't fail if left or right are NULL.
[Edit]Adam Rosenfield made me realize this was incorrect if there was loops in the network. Had to rewrite almost from scratch. Due to the large amount of code required, I prefer his code's for loop.
return new Node(*node);
Trick question?
You should write it recursively;
Node * Copy( Node * root )
{
Node * node_copy;
node_copy = new Node; // Assume Node1 and Node2 are initialized to 0
node_copy->content = root->content;
if( root->Node1 ) node_copy->Node1 = Copy( root->Node1 );
if( root->Node2 ) node_copy->Node2 = Copy( root->Node2 );
return node_copy;
}
So, this does not make any assumption on the data type
Given that a copy constructor exists that copies only the contents of a node and not its children:
Node* Copy(Node* root)
{
Node* copy = new Node(*root);
copy->left = Copy(root->left);
copy->right = Copy(root->right);
return copy;
}
In a more general sense, I would use copy-constructors that fully copy the entire data structure:
Node* Copy(Node* root)
{
return new Node(*root);
}