Binary tree deletion-cannot understand some pointers - c

I have a doubt in this binary tree deletion.The code is
#include<stdio.h>
#include<stdlib.h>
struct node
{
int key;
struct node *left, *right;
};
struct node *newNode(int item)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}
void inorder(struct node *root)
{
if (root != NULL)
{
inorder(root->left);
printf("%d ", root->key);
inorder(root->right);
}
}
struct node* insert(struct node* node, int key)
{
if (node == NULL) return newNode(key);
if (key < node->key)
node->left = insert(node->left, key);
else
node->right = insert(node->right, key);
return node;
}
struct node * minValueNode(struct node* node)
{
struct node* current = node;
while (current->left != NULL)
current = current->left;
return current;
}
struct node* deleteNode(struct node* root, int key)
{
if (root == NULL) return root;
if (key < root->key)
root->left = deleteNode(root->left, key);
else if (key > root->key)
root->right = deleteNode(root->right, key);
else
{
if (root->left == NULL)
{
struct node *temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL)
{
struct node *temp = root->left;
free(root);
return temp;
}
struct node* temp = minValueNode(root->right);
root->key = temp->key;
root->right = deleteNode(root->right, temp->key);
}
return root;
}
int main()
{
struct node *root = NULL;
root = insert(root, 50);
root = insert(root, 30);
root = insert(root, 20);
root = insert(root, 40);
root = insert(root, 70);
root = insert(root, 60);
root = insert(root, 80);
printf("Inorder traversal of the given tree \n");
inorder(root);
printf("\nDelete 20\n");
root = deleteNode(root, 20);
printf("Inorder traversal of the modified tree \n");
inorder(root);
printf("\nDelete 30\n");
root = deleteNode(root, 30);
printf("Inorder traversal of the modified tree \n");
inorder(root);
printf("\nDelete 50\n");
root = deleteNode(root, 50);
printf("Inorder traversal of the modified tree \n");
inorder(root);
return 0;
}
The lines which I cannot understand is:
if (root->left == NULL)
{
struct node *temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL)
{
struct node *temp = root->left;
free(root);
return temp;
}
is this code actually return NULL value then can I rewrite the code as struct node *temp=NULL in both the cases but the last inorder value is not displayed when i do this.

The code you are inquiring about is part of the code handling the case that the node to delete is the root node of the tree. It checks whether the root node has only one child (or zero), in which case the deletion can be performed simply by making the one child the new root of the tree.
Note in particular that when root->left == NULL it is the right child, not the left one, that is chosen as the new root (and temporarily recorded in temp), and vice versa. Either way, the original root node is freed since it is no longer in the tree, and will not be accessible via the new root pointer that the function is about to return.
The function returns NULL only when the root node is initially the only node in the tree.

Related

How to implement a function that iteratively creates a binary tree?

I tried to implement a binary tree by using an iterative function to create it. I'm quite confused about why I'm getting an infinite loop as my output. I believe that the function being used is not having problems. But if anyone can explain me what exactly is causing this error I would appreciate it.
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
int data;
struct node *left,*right;
} NODE;
NODE* createNode(int ele){
NODE* newnode = (NODE*)malloc(sizeof(NODE));
newnode->data = ele;
newnode->left = NULL;
newnode->right = NULL;
return newnode;
}
void inorder(NODE* root){
while(root != NULL){
inorder(root->left);
printf(" %d ",root->data);
inorder(root->right);
}
}
void preorder(NODE* root){
while(root != NULL){
printf(" %d ",root->data);
preorder(root->left);
preorder(root->right);
}
}
void postorder(NODE* root){
while(root != NULL){
postorder(root->left);
postorder(root->right);
printf(" %d ",root->data);
}
}
void createTree(NODE** root, int ele){
NODE* newnode = createNode(ele);
if(*root == NULL){
//set newnode as root
*root = newnode;
return;
}
NODE* curr = *root;
while (1){
// If the data of the new node is less than the data of the current node,
// go to the left child
if(ele < curr->data){
// If the left child is empty, insert the new node here
if(curr->left == NULL){
curr->left = newnode;
return;
}
curr = curr->left;
}
// If the data of the new node is greater than or equal to the data of the current node,
// go to the right child
else{
if (curr->right == NULL){
curr->right = newnode;
return;
}
curr = curr->right;
}
}
}
int main(){
NODE* root = NULL;
int data;
while(1){
printf("Enter the data for the root node of the binary tree(Enter -1 to stop): \n");
scanf("%d",&data);
createTree(&root,data);
if(data == -1){
break;
}
}
printf("\nPreorder traversal:\n");
preorder(root);
printf("\nInorder traversal:\n");
inorder(root);
printf("\nPostorder traversal:\n");
postorder(root);
return 0;
}
In the print functions, the line
while(root != NULL){
will cause endless looping as root never change.
You probably want
if(root != NULL){

C tree, delete an element if a condition is met

i have implemented a tree in C:
struct node
{
char *key;
struct node *left, *right;
};
// A utility function to create a new BST node
struct node *newNode(char *item)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}
// A utility function to do inorder traversal of BST
void inorder(struct node *root)
{
if (root != NULL)
{
inorder(root->left);
printf("%s\n", root->key);
inorder(root->right);
}
}
/* A utility function to
insert a new node with given key in
* BST */
struct node *insert(struct node *node, char *key)
{
/* If the tree is empty, return a new node */
if (node == NULL)
return newNode(key);
/* Otherwise, recur down the tree */
if (strcmp(key, node->key) < 0)
node->left = insert(node->left, key);
else
node->right = insert(node->right, key);
/* return the (unchanged) node pointer */
return node;
}
/* Given a non-empty binary search
tree, return the node
with minimum key value found in
that tree. Note that the
entire tree does not need to be searched. */
struct node *minValueNode(struct node *node)
{
struct node *current = node;
/* loop down to find the leftmost leaf */
while (current && current->left != NULL)
current = current->left;
return current;
}
/* Given a binary search tree
and a key, this function
deletes the key and
returns the new root */
struct node *deleteNode(struct node *root, char *key)
{
// base case
if (root == NULL)
return root;
// If the key to be deleted
// is smaller than the root's
// key, then it lies in left subtree
if (strcmp(key, root->key) < 0)
root->left = deleteNode(root->left, key);
// If the key to be deleted
// is greater than the root's
// key, then it lies in right subtree
else if (strcmp(key, root->key) > 0)
root->right = deleteNode(root->right, key);
// if key is same as root's key,
// then This is the node
// to be deleted
else
{
// node with only one child or no child
if (root->left == NULL)
{
struct node *temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL)
{
struct node *temp = root->left;
free(root);
return temp;
}
// node with two children:
// Get the inorder successor
// (smallest in the right subtree)
struct node *temp = minValueNode(root->right);
// Copy the inorder
// successor's content to this node
root->key = temp->key;
// Delete the inorder successor
root->right = deleteNode(root->right, temp->key);
}
return root;
}
I have defined a function that takes the Tree as input and deletes a node from it if a condition is met:
void applyFilter(struct node *Tree)
{
if (Tree != NULL)
{
applyFilter(Tree->left);
applyFilter(Tree->right);
for (short i = 0; i < MAX_CONSTRAINTS; i++)
{
if (strchr(Tree->key, constraints[i].letter) != NULL)
{
// delete the word from the tree
Tree = deleteNode(Tree, Tree->key);
break;
}
}
}
}
But i got segmentation fault.
The main goal is to make it work, with as little memory as possible (running).
I think I understand the problem, and it is caused by recursion, because if I delete a node it will give me an empty tree.
If you can give me an example, even a different one i will be really gratefull, because i worked on it a lot, but i am totally stucked.
Thank you!
It happens in minValueNode() after the call of the deleteNode(), because result that the Tree is empty
It happens in minValueNode() after the call of the deleteNode(), because result that the Tree is empty
Basically you already understand what the problem is. You will need to check whether the tree is empty and default the value to something inside minValueNode before you start looping. Because the loop assumes that you have something and if you happen to have nothing, then it's a faulty assumption and causes segfault.

C Binary Tree Deletion Not Working Inorder Print Causes Infinite Recursion

I'm learning binary trees, and I'm trying to delete a node from the binary tree. I get a segmentation fault after infinite recursion in the print in order function. It only does this after the delete function is called. I don't get why this happened. I think it should only happen if the last left pointer in the tree is set to something other than NULL, which would cause the if statement to return to never be triggered. The delete function in this particular case is deleting a node on the right so it shouldn't even touch anything on the left. Help would be appreciated.
#include <stdio.h>
#include <stdlib.h>
struct Node{
//blueprint for node
int data;
struct Node *Left;
struct Node *Right;
};
struct Node *CreateNode(int data){
//utility function to create a new node
struct Node *newNode = malloc(sizeof(struct Node));
newNode->Left = NULL;
newNode->Right = NULL;
newNode->data = data;
return newNode;
}
struct Node *insertNode(struct Node *root, int num){
if(root == NULL){
root = CreateNode(num);
return root;
}
if(root->data >= num){
if(root->Left != NULL){
insertNode(root->Left, num);
}
else{
//if the node on the left of root is equal to NULL
//create a node
root->Left = CreateNode(num);
}
}
else{
if(root->Right != NULL){
insertNode(root->Right, num);
}
else{
//if the node on the right of root is equal to NULL
//create a node
root->Right = CreateNode(num);
}
}
}
void inOrderPrint(struct Node *Head){
//prints nodes in the binary tree in order
if(Head == NULL){
//if the head is null, stop doing recursion
return;
}
//recursivly calls itself and passes in the left node as a parameter
if(Head->Left != NULL){
inOrderPrint(Head->Left);
}
//prints out the data at the current node
printf("%d ", Head->data);
//recusivly calls itself and pases in the right node as a peramater
if(Head->Right != NULL){
inOrderPrint(Head->Right);
}
}
int getHeight(struct Node *Head){
//gets the height of the binary tree
if(Head == 0){
return -1;
}
int left = getHeight(Head->Left)+1;
int right = getHeight(Head->Right) + 1;
if(left > right){
return left;
}
else{
return right;
}
}
int childNum(struct Node *Head){
//returns the number of children the binary search tree node has (directly below it, not counting grand children)
if(Head->Left == NULL && Head->Right == NULL){
//if there is no child
return 0;
}
else if(Head->Left == NULL || Head->Right == NULL){
//if there 1 child
return 1;
}
else{
//if there are two children
return 2;
}
}
int getMax(struct Node *root){
if(root->Right == NULL){
return root->data;
}
else{
return getMax(root->Right);
}
}
struct Node *DeleteNode(struct Node *root, int num){
//function to delete a node from the binary search tree
if(root == NULL){
return root;
}
if(root->data == num){
//if this is the node to be deleted
int numberOfChildren = childNum(root);
if(numberOfChildren == 0){
printf("here??");
free(root);
return NULL;
}
else if(numberOfChildren == 1){
if(root->Left == NULL){
struct Node *temp = root->Right;
free(root);
return temp;
}
else{
struct Node *temp = root->Left;
free(root);
return temp;
}
}
else{
int max = getMax(root->Left);
root->data = max;
DeleteNode(root->Left, max);
return root;
}
}
else if(root->data >= num){
//if this node is greater than or equal to the node to be deleted, recur to the node on the left
root->Left = DeleteNode(root->Left, num);
}
else{
//if this node is less than the node to be deleted, recur to the node on rhe right
root->Right = DeleteNode(root->Right, num);
}
return root;
}
int main()
{
struct Node *root = NULL;
root = insertNode(root, 5);
insertNode(root, 10);
insertNode(root, 3);
insertNode(root, 14);
insertNode(root, 7);
insertNode(root, 16);
inOrderPrint(root);
printf("\nheight: %d", getHeight(root));
DeleteNode(root, 10);
printf("root left: %d", root->Left->data);
printf("\n");
inOrderPrint(root);
//sprintf(result, "%d/%f ...", int);
}

Not deleting node with two children

When deleting a node with two children from my binary tree of "products", rather than replacing the root to delete with it's left child's most right ancestor and then deleting that descendant, it is simply just replacing that root's value with ancestors value. I have called "free()" on that ancestor but that doesn't seem to work. So what I am left with is two nodes of the same value.
My code:
#include <stdio.h>
#include <stdlib.h>
//Structures
typedef struct Node{
void *dataPtr;
struct Node *left;
struct Node *right;
}node;
typedef struct Product
{
int ProductCode;
char ProductName[30];
int QuantityOnHand;
double ProductCost;
double ProductRetail;
char ProductLocationCode[7];
}product;
//functions
int compareID(void *ptr1, void *ptr2)
{
int temp;
if (((product *)ptr1)->ProductCode > ((product *)ptr2)->ProductCode)
temp = 1;
else
if (((product *)ptr1)->ProductCode < ((product *)ptr2)->ProductCode)
temp = -1;
else
temp = 0;
return temp;
}
void insert(node ** root, node** val, int(*f)(void*,void*)){
if (!(*root)) {
//initalize a temporary node
node *temp = NULL;
temp = (node *)malloc(sizeof(node));
//make both right and left nodes for temp to be NULL
temp->left = NULL;
temp->right = NULL;
temp->dataPtr = (*val)->dataPtr;//store value you were looking for in temp
*root = temp;// root is now the temporary node
return;//end of function.
}
int result = f((*root)->dataPtr, (*val)->dataPtr);
if (result == 1) {//if the value is less than the current root node, go to the left connecting node
insert(&(*root)->left, &(*val), f);
}
else if (result == -1) {//if the value is more than the current root node, go to the right connecting node
insert(&(*root)->right, &(*val), f);
}
}
struct Node* deleteNode(struct Node *root, void *ptr, int(*cptr)(void*, void*))
{
struct Node *temp;
if (cptr(ptr, root->dataPtr) == 0)
{
if (root->left == NULL && root->right == NULL)//no children
{
free(root);
return NULL;
}
if (root->left != NULL && root->right == NULL)//left child
{
temp = root->left;
free(root);
return temp;
}
if (root->left == NULL && root->right != NULL)//right child
{
temp = root->right;
free(root);
return temp;
}
else //two children
{
struct Node* pred = root->left;//go left one of the node you're trying to delete
while (pred->right != NULL){//now get further right ancestor of that node
pred = pred->right;
}
root->dataPtr = pred->dataPtr; //make the original node the value of that right ancestor
return pred;//return that ancestor to delete it
}
}
else
{
int val = cptr(ptr, root->dataPtr);
if (val < 0)
{
root->left = deleteNode(root->left, ptr, cptr);
return root;
}
else
{
root->right = deleteNode(root->right, ptr, cptr);
return root;
}
}
}
void readData(struct Node** vptr, FILE *fp){
product* ptr = (product *)malloc(sizeof(product));
if (fp == stdin){
printf("Enter Product Code: ");
fscanf(fp, "%d", &(ptr->ProductCode));
fflush(stdin);
printf("Enter Name: ");
fscanf(fp, "%30[^\n]", ptr->ProductName);
fflush(stdin);
printf("Enter Quantity: ");
fscanf(fp, "%d", &(ptr->QuantityOnHand));
printf("Enter Cost: ");
fscanf(fp, "%lf", &(ptr->ProductCost));
fflush(stdin);
ptr->ProductRetail = (ptr->ProductCost / 0.7);
printf("Enter Location: ");
fscanf(fp, "%6[^\n]", &(ptr->ProductLocationCode));
fflush(stdin);
}
else{
fscanf(fp, "%d %29[^\n] %d %lf %6[^\n]", &(ptr->ProductCode), ptr->ProductName, &ptr->QuantityOnHand, &ptr->ProductCost, &ptr->ProductLocationCode);
ptr->ProductRetail = (ptr->ProductCost / 0.7);
}
(*vptr)->dataPtr = ptr;
}
int main()
{
int i = 0;
struct Node *newNode, *temp;
struct Node *root = NULL;
int(*compPtr)(void *, void *) = compareID;
for(i; i < 3; i++){
newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->left = newNode->right = NULL;// missing this operation.
readData(&newNode, stdin); // this function call was missing.
insert(&root, &newNode, compPtr);
}
temp = (struct Node *)malloc(sizeof(struct Node));
temp->dataPtr = malloc(sizeof(struct Product));
printf("enter the product ID to delete : ");
fflush(stdin);
scanf("%d", &((struct Product *)temp->dataPtr)->ProductCode);
deleteNode(root, temp->dataPtr, compPtr);
free(temp->dataPtr);
free(temp);
return 0;
}
Why is this ancestor node not being freed from memory? What should I change in order to make sure it is deleted?
Your question and code are confusing at first because you use the word "ancestor" when you mean "descendant." Child nodes are descendants. Ancestors are those that come before.
The problem appears to be that you're returning the descendant rather than deleting it. In all the other cases, you're deleting the root and returning the new node. In the case that's causing you trouble, you're not deleting any node. Instead, you're returning the left child's rightmost descendant. The code that calls deleteNode replaces the node to be deleted with the node that is returned.
In this case you need to return the root after deleting the node whose value replaced the root's value. But before you can delete that descendant node, you have to remove the link from that node's parent.
I think the code you want is:
//go left one of the node you're trying to delete
struct Node* parent = root;
struct Node* pred = root->left;
//now get further right descendant of that node
while (pred->right != NULL){
parent = pred;
pred = pred->right;
}
//make the original node the value of that right descendant
root->dataPtr = pred->dataPtr;
// unlink that node from its parent
if (parent == root)
parent->left = NULL;
else
parent->right = NULL;
free(pred);
return root; //return the root node

Recursive code for searching max height of binary tree

I've created a tree using this code (this is outdated look at the bottom, problem updated):
struct node* buildTree() {
struct node* root = NULL;
root = insert(root, 2);
root = insert(root, 4);
root = insert(root, 10);
return(root);
}
Then tried to find max depth of that (functions Max and insert work properly), using this:
int maxHeight(struct node* p) {
if(p == NULL) {return 0;}
else{
int leftDepth = 1 + maxHeight(p->left);
int rightDepth = 1 + maxHeight(p->right);
return(Max(leftDepth, rightDepth));
}
}
And it shows me error like max depth is 3; I've compiled in C99 standard. I've found this and similar code in several places in the Internet, but here doesn't work, any ideas what's wrong? Thanks..
As suggested adding insert code:
struct node* insert(struct node* node, int data) {
if (node == NULL) {
return(newNode(data));
}
else {
if (data <= node->data) node->left = insert(node->left, data);
else node->right = insert(node->right, data);
return(node);
}
}
And newNode function:
struct node* newNode(int data) {
struct node* node = malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
Update:
New buildTree function:
struct node* buildTree() {
struct node* root = newNode(3);
root->left = newNode(2);
root->right = newNode(1);
return(root);
}
The code works but it looks like the tree you built is not what you meant, probably as you keep concatenating a new node to the previous node (and not to the single root).
Assuming the insert returns the node just created then your first add a tree node 2:
Tree: (2)
The you're adding a tree node 4 as a child of tree node 2:
Tree: (2)--(4)
Finally you're adding a tree node 10 as a child of tree node 4:
Tree: (2)--(4)--(10)
So as you can see the tree depth is 3 (including the root).

Resources