Having trouble with a binary search tree remove function - c

I'm attempting to remove a given value from a binary search tree. The function returns 1 if the given value was present, and 0 if it wasn't. I don't think I'm returning values properly. The proper values seem to be removed, but I'm printing a removal message when I shouldn't be, indicating that the function is returning 0 when it shouldn't be. Can anybody help me spot my error? Thanks.
/*Remove data from BST pointed to by rootRef, changing root if necessary.
* For simplicity's sake, always choose node's in-order
* successor in the two-child case.
* Memory for removed node should be freed.
* Return 1 if data was present, 0 if not found. */
int removeBST(struct TreeNode** rootRef, int data)
{
struct TreeNode* heir;
struct TreeNode* prev;
if(*rootRef == NULL)
{
return 0;
}
if(data < (*rootRef)->data)
{
removeBST(&(*rootRef)->left, data);
}
else if(data > (*rootRef)->data)
{
removeBST(&(*rootRef)->right, data);
}
else
{
struct TreeNode* temp;
if((*rootRef)->right == NULL)
{
temp = *rootRef;
*rootRef = (*rootRef)->left;
free(temp);
}
else if((*rootRef)->left == NULL)
{
temp = *rootRef;
*rootRef = (*rootRef)->right;
free(temp);
}
else
{
heir = (*rootRef)->left;
prev = *rootRef;
while(heir->right != NULL)
{
prev = heir;
heir = heir->right;
}
(*rootRef)->data = heir->data;
if(prev != *rootRef)
{
prev->right = heir->left;
}
else
{
prev->left = heir->left;
}
free(heir);
}
return 1;
}
return 0;
}

When it calls itself recursively, it needs to return the value from the recursive call. So change:
removeBST(&(*rootRef)->left, data);
to:
return removeBST(&(*rootRef)->left, data);
and similarly for the right-hand case. Without this, it is just falling through and returning 0 for these cases.

Replace
if(data < (*rootRef)->data)
{
removeBST(&(*rootRef)->left, data);
}
else if(data > (*rootRef)->data)
{
removeBST(&(*rootRef)->right, data);
}
with
if(data < (*rootRef)->data)
{
return removeBST(&(*rootRef)->left, data);
}
else if(data > (*rootRef)->data)
{
return removeBST(&(*rootRef)->right, data);
}
When you call the function, you did not use the return value.

Related

C Order Statistic Tree: Recursive Deletion Node Counting

I am trying to make an order statistic tree of some sort where I have to keep track of the size (nodeCount variable on each node) recursively. It orders a tree of objects by comparing the memory locations. I just need help on the delete recursive method, which I have figured out besides how to count the nodes for deletion. I will include my fully working insert method as an example. Any help would be appreciated, thank you :)
DELETE RECURSIVE (NEED HELP)
`
bool deleteR(TreeKey k, TreeNode** tptr) {
TreeNode* curr = *tptr;
// base case: root contains null
if (curr == NULL) {
// node not there: return false
return false;
}
else if(less(k, getKey(curr->value))) {
// our data is less, so go left
return deleteR(k, &curr->left);
}
else if(less(getKey(curr->value), k)) {
// our data is greater, so go right
return deleteR(k, &curr->right);
}
// at this point, we've found our node
// if either of the current node's subtrees is null:
// - replace the current node in the tree with the "other" subtree
// - free the current node
// - return true
if (curr->left == NULL) {
*tptr = curr->right;
free(curr);
return true;
}
else if (curr->right == NULL) {
*tptr = curr->left;
free(curr);
return true;
}
// call helper-function
inorderSuccessorReplace(curr, &curr->right);
return true;
}
static void inorderSuccessorReplace(TreeNode* target, TreeNode** spot) {
TreeNode* curr = *spot;
if (curr->left == NULL) {
// found our spot
target->value = curr->value;
*spot = curr->right;
free(curr);
}
else {
inorderSuccessorReplace(target, &curr->left);
}
}
`
INSERT RECURSIVE METHOD
`
bool insertR(TreeData d, TreeNode **tptr) {
TreeKey key = getKey(d);
if(*tptr == NULL) {
*tptr = newTreeNode(d);
(*tptr)->nodeCount = size(*tptr); // updates nodeCount
return true;
}
else if(less(key, getKey((*tptr)->value))) {
(*tptr)->nodeCount = size(*tptr) + 1; // updates nodeCount
// item is less: recursively insert to the left
return insertR(d, &(*tptr)->left);
}
else if(less(getKey((*tptr)->value), key)) {
(*tptr)->nodeCount = size(*tptr) + 1; // updates nodeCount
// item is greater: recursively insert to the right
return insertR(d, &(*tptr)->right);
}
else {
// item already in the tree: return false
return false;
}
}
int size(TreeNode* t) {
if (t == NULL) {
return 0;
}
return t->nodeCount;
}
`

Insert of a new node into a binary tree and return its head pointer

Hello i need to make a function that inserts a new node into a binary search tree and returns a pointer to the head/root of that tree.
My problem is with the returned value, i cant seem to figure out how to return the head of the tree in a recursive way as seen below.
tree_type insertNode (tree_type tree, int data) {
tree_type temp = NULL;
if(!tree)
{
temp = (tree_type)malloc(3*sizeof(tree_type));
temp->left = temp->right = NULL;
temp->data = data;
tree = temp;
return ;
}
if(data < tree->data)
{
insertNode(tree->left, data);
}
else if(data > tree->data)
{
insertNode(tree->right, data);
}
}
Firstly, the assignment tree = temp is useless, because tree is a local variable which disappears when the function returns.
Secondly, a return; in a function which is declared as returning a type other than void requires a diagnostic; it is not valid C or C++.
Instead of
tree = temp;
return;
consider returning the new tree:
return temp;
(There is no need for the variable temp; you could just use the variable tree in that case and then return tree).
The problem of how to return the root node is simple:
if(data < tree->data)
{
tree->left = insertNode(tree->left, data);
return tree;
}
and so forth. If you eliminate the variable temp and use tree in the malloc case, your function can just have a single return point which consists of return tree;.
If tree->left is null, then insertNode(tree->left, data) receives a null left argument and so receives a new node. We must capture this return value and assign it to tree->left. If tree->left is not null, then insertNode will just return tree->left and so the assignment just writes the same value back into tree->left.
Is that what you need?
if(!tree)
{
temp = (tree_type) malloc(sizeof(*temp));
temp->left = temp->right = NULL;
temp->data = data;
return temp;
}
if(data < tree->data)
{
tree->left = insertNode(tree->left, data);
return tree->left;
}
else if(data > tree->data)
{
tree->right = insertNode(tree->right, data);
return tree->right;
}

Validate the claim that it is better to use pointers to pointers while working with binary trees

In this video (a section/recitation for an online course called CS50), around 1h00m00s, the student instructor goes into pointers-to-pointers and why it is more efficient useful to implement insert on the binary tree this way. At least, that is what I'm getting from the argument.
I did a recursive implementation both ways. I don't see why Option A is better than Option B in the below...perhaps you could help me reason this out or point me in the right direction if I'm misunderstood?
Option A (with pointers-to-pointers)
bool insert(int value, node* tree)
{
node** tmptree = &tree;
// make sure the tree itself isn't null
if(*tmptree != NULL)
{
if(value == (*tmptree)->value)
{
return false;
}
else if(value < (*tmptree)->value)
{
tmptree = &(*tmptree)->left;
// we must be at a null leaf!
if(*tmptree == NULL)
{
// make sure we built a leaf
*tmptree = build_node(value);
if(*tmptree == NULL)
{
return false;
}
return true;
}
else
{
return insert(value, *tmptree);
}
}
else
{
tmptree = &(*tmptree)->right;
if(*tmptree == NULL)
{
*tmptree = build_node(value);
if(*tmptree == NULL)
{
return false;
}
return true;
}
else
{
return insert(value, *tmptree);
}
}
}
return false; // if the tree is null
}
Option B (regular ptrs)
bool insert(int value, node* tree)
{
if(tree != NULL)
{
if(value == tree->value)
{
return false;
}
else if(value < tree->value)
{
if(tree->left == NULL)
{
node* tmp = build_node(value);
if(tmp != NULL)
{
tree->left = tmp;
return true;
}
return false;
}
else
{
return insert(value, tree->left);
}
}
else
{
if(tree->right == NULL)
{
node* tmp = build_node(value);
if(tmp != NULL)
{
tree->right = tmp;
return true;
}
return false;
}
else
{
return insert(value, tree->right);
}
}
}
return false; // if the tree is null
}
The build_node function:
node* build_node(int value)
{
node* node = malloc(sizeof( node ));
if(node == NULL)
return NULL;
node->value = value;
node->left = NULL;
node->right = NULL;
return node;
}
I believe you have misunderstood why there is a pointer-to-pointer in the original code. The "Option a" doesn't make any sense, there is no advantage of using pointer-to-pointer just for the sake of it.
The only reason you would use pointer-to-pointer is because you want to change the pointed-to address and return it to the caller.
For example
void func (int** ptr)
{
*ptr = something;
}
func(&my_ptr);
// is the very thing same as
int* func (int* ptr)
{
return something;
}
my_ptr = func(my_ptr);
You can't use the second version and type ptr = something inside the function, because ptr is a local variable and will cease to exist once you leave the function. Assigning something to it won't affect the original pointer at the caller's side.
The only advantage of the pointer-to-pointer version is that the returned type can be used for something else, like for example returning an error code.
And that seems to be exactly why the guy in that video used it. His function looks like
bool insert (int value, node** tree);
where the *tree is assigned to point at another address from inside the function and the bool is used as a status code, when he reaches the end of a tree branch.

Why do we need to return the head pointer in a BST after inserting node?

#include<stdio.h>
#include<stdlib.h>
typedef struct BTreeNode BTNode;
struct BTreeNode
{
int value;
struct BTreeNode *left_child,*right_child;
};
BTNode* insert(int input_value, BTNode **head_node)
{
BTNode *temp,*head;
temp = malloc(sizeof(BTNode));
temp->value = input_value;
temp->left_child = NULL;
temp->right_child = NULL;
head = *head_node;
while(1)
{
if(head == NULL)
{
head = temp;
// break;
return head;
}
if(temp->value > head->value)
{
if(head->right_child == NULL)
{
head->right_child=temp;
}
else
head = head->right_child;
}
else if(temp->value < head->value)
{
if(head->left_child == NULL)
{
head->left_child=temp;
}
else
head = head->left_child;
}
else
{
break;
}
}
return *head_node;
}
int insert_wor(int input_value, BTNode **head_node)
{
BTNode *temp,*head;
temp = malloc(sizeof(BTNode));
temp->value = input_value;
temp->left_child = NULL;
temp->right_child = NULL;
head = *head_node;
while(1)
{
if(head == NULL)
{
head = temp;
// break;
return 1;
}
if(temp->value > head->value)
{
if(head->right_child == NULL)
{
head->right_child=temp;
}
else
head = head->right_child;
}
else if(temp->value < head->value)
{
if(head->left_child == NULL)
{
head->left_child=temp;
}
else
head = head->left_child;
}
else
{
return -1;
}
}
return 1;
}
void printtree(BTNode **head_node)
{
BTNode *head;
head = *head_node;
if(head == NULL)
{
// printf("Print exit\n");
return;
}
else
{
printf("%d\n",head->value);
printtree(&(head->left_child));
printtree(&(head->right_child));
}
}
int main()
{
BTNode *root=NULL,*root_wor=NULL;
root=insert(23,&root);
root=insert(32,&root);
root=insert(230,&root);
root=insert(3,&root);
root=insert(2,&root);
root=insert(50,&root);
printtree(&root);
insert_wor(24,&root_wor);
insert_wor(42,&root_wor);
insert_wor(45,&root_wor);
insert_wor(12,&root_wor);
insert_wor(87,&root_wor);
insert_wor(123,&root_wor);
printtree(&root_wor);
}
In the above code I have written two different functions to insert node in a BST.
1)In one function I am returning the head pointer after inserting a node in it.
2)In the second function I am not returning the head pointer.
when I am trying to print the BST first one is working fine but I am not able to print
second BST.
My doubt is as per the concept of pointers even though we make changes in the member function it should reflect in the main function, but in this case(In the second method when I am passing head and making changes to it in member function they are not reflecting in main function) that is not happening??
I think I am getting confused at some point. Could anyone please help out in clarifying this??
Thanks
In the second version, head = *head_node; copies the head pointer. When you change head later on, the original pointer (pointed to by head_node) won't ever get updated. If you always used *head_node instead of a copy of it, or if you assigned *head_node = head; before returning, then the insert_wor() function would work as well.

Iteratively inserting into a binary tree

I came across some threads on StackOverflow but none of them quite cleared my doubts.
So the problem is simple. I need to iteratively insert elements into a binary tree. And this is my code.
BST newNode(int x)
{
BSTNodePtr node = (BSTNodePtr) malloc(sizeof(struct TreeNode));
node->Element = x;
node->Left = NULL;
node->Right = NULL;
return node;
}
BST Insert(int x, BST T)
{
BST temp_node = T;
while( T != NULL) {
if (x < T->Element)
T = T->Left;
else if (x >= T->Element)
T = T->Right;
}
T = newNode(x);
return temp_node;
}
However, when I'm finding the height of this tree I am always getting 0. The height code is
int Height(BST T)
{
if (T == NULL)
return 0;
return 1+(max(Height(T->Left), Height(T->Right)));
}
and this works perfectly fine when I do insertion recursively (using a function with the exact same signature)
What am I missing?
Here:
BST Insert(int x, BST T)
{
BST temp_node = T;
while( T != NULL) {
if (x < T->Element)
T = T->Left;
else if (x >= T->Element)
T = T->Right;
}
T = newNode(x);
return temp_node;
}
You navigate the tree until you hit T == NULL. Then you create a node and assign the pointer to it to T. Then you return the original value of T. You don't modify your tree at all. No node in it is made to point to the newly created node. T is just a local variable.
Couldn't solve the problem that way. This code, however, seems to work.
BST Insert(int x, BST T)
{
BST temp=T;
BST node=(BST)malloc(sizeof(struct TreeNode));
node->Element=x;
node->Left=NULL;
node->Right=NULL;
if (T==NULL)
{
T=node;
return(T);
//printf("%d\n",T->Element);
}
else
{
while(1)
{
if (temp->Element>=node->Element && temp->Left==NULL)
{
temp->Left=node;
break;
}
else if (temp->Element>=node->Element && temp->Left!=NULL)
{
temp=temp->Left;
}
else if (temp->Element<node->Element && temp->Right==NULL)
{
temp->Right=node;
break;
}
else
{
temp=temp->Right;
}
}
return(T);
}
}
Here's My implementation of the aforementioned problem:
bst* newNode(int x)
{
bst* T = new bst;
T->value = x;
T->left_child = T->right_child = NULL;
return T;
}
bst* bst_insert_iter(bst* T,int val)
{
if (T == NULL)
T = newNode(val);
else
{
bst *temp_node = T;
bool flag = true;
while(flag)
{
if (val <= temp_node->value)
{
if (temp_node->left_child == NULL)
{
temp_node->left_child=newNode(val);
flag = false;
}
else
temp_node = temp_node->left_child;
}
else
{
if (temp_node->right_child == NULL)
{
temp_node->right_child=newNode(val);
flag = false;
}
else
temp_node = temp_node->right_child;
}
}
}
return T;
}
You have the bug in your insert function. As I may assume, initially your tree is empty. so the first time you insert a node, the second argument is NULL, right? Then this function always returns NULL to you as you always pass a NULL value.
template <class T>
class TreeNode{
private:
T data;
TreeNode<T>* right,*left;
public:
void setData(T d){
this->data =d;
}
T getData(){
return this->data;
}
void setRight(TreeNode<T>* r){
this->right =r;
}
TreeNode<T>* getRight(){
return this->right;
}
void setLeft(TreeNode<T>* r){
this->left =r;
}
TreeNode<T>* getLeft(){
return this->left;
}
static TreeNode<T>* newNode(T data){
TreeNode<T>* n = new TreeNode<T>();
n->setData(data);
n->setRight(NULL);
n->setLeft(NULL);
return n;
}
};
template <class T>
class BinaryTree{
private:
TreeNode<T>* root;
public:
void insert(T data){
TreeNode<T>* n = TreeNode<T>::newNode(data);
if(root==NULL)
root = n;
else{
TreeNode<T>* t = root;
while(t!=NULL){
if(n->getData() >= t->getData()){
if(t->getRight()==NULL){
t->setRight(n); //newnode attached as right child in tree
t = NULL;
}
else
t = t->getRight();
}
else{
if(t->getLeft()==NULL){
t->setLeft(n); //newnode attached as left child in tree
t=NULL;
}
else
t = t->getLeft();
}
}
}
}
void preorder(){
TreeNode<T>* t = root;
preorderUtil(t);
}
void preorderUtil(TreeNode<T>* node){
if(node==NULL)
return;
preorderUtil(node->getLeft());
cout<<node->getData()<<" ";
preorderUtil(node->getRight());
}
};
Your changes are not reflected in the tree. I followed this way to insert data iteratively and it works fine. The point is making a node inside your binarytree to point the newly created node such that it gets attached to the tree.
Here is my version , it seems to be working.
struct tree{
tree *left;
tree *right;
int key;
};
void insertBst(int k,tree *t)
{
tree *newK = new tree[sizeof(tree)];
newK->key = k;
newK->left = NULL;
newK->right = NULL;
if((t)->key == NULL)
{
t=newK;
return;
}
else{
bool found = false;
tree *root = t;
tree *parent = NULL;
while(root != NULL)
{
parent = root;
if(root->key < newK->key)
{
root=root->right;
}
else if(root->key > newK->key)
{
root=root->left;
}
else{
//Here we have duplicates!! so do nothing
root = root;
}
}
if(parent->key > newK->key) parent->left = newK;
else parent->right = newK;
}
}

Resources