i was trying to understand this function founded online for deleting a node from a BST. There are some things i can't understand
This is the code :
struct Node* Delete(struct Node *root, int data) {
if (root == NULL) {
return NULL;
}
if (data > root->data) { // data is in the left sub tree.
root->left = Delete(root->left, data);
} else if (data > root->data) { // data is in the right sub tree.
root->right = Delete(root->right, data);
} else {
// case 1: no children
if (root->left == NULL && root->right == NULL) {
delete(root); // wipe out the memory, in C, use free function
root = NULL;
}
// case 2: one child (right)
else if (root->left == NULL) {
struct Node *temp = root; // save current node as a backup
root = root->right;
delete temp;
}
// case 3: one child (left)
else if (root->right == NULL) {
struct Node *temp = root; // save current node as a backup
root = root->left;
delete temp;
}
// case 4: two children
else {
struct Node *temp = FindMin(root->right); // find minimal value of right sub tree
root->data = temp->data; // duplicate the node
root->right = Delete(root->right, temp->data); // delete the duplicate node
}
}
return root; // parent node can update reference
}
Questions :
1) Why it is
if (data > root->data) { // data is in the left sub tree.
root->left = Delete(root->left, data);
shouldn't it be if(data < root->data) ? (same for the two lines of code right after)
2) the function return a pointer to node,does that mean that in the main function i have to do something like this?
int main(){
struct Node *tree=malloc(sizeof(Node));
...
struct Node *new_tree=malloc(sizeof(Node));
new_tree= Delete(tree,24);
So the function replace the old tree with a new tree without the node with the val 24?if i want the function to be of type void should i use double pointers?
For your first question you have right it should be: if(data < root->data).
For the second question not exactly. You obviously should define a pointer head which is the head of the tree and create an function which inserts data to bst, so this function does the malloc. All you nead in your main is the head pointer initialized to NULL in the beginning so it should look like:
int main(){
struct Node *tree=NULL;
int number=...;
...
input_to_bst(&tree,number);
...
new_tree= Delete(tree,24);
Also note that new tree doesn't need to have malloc since your function returns a pointer that already shows to a struct and what you do is that new_tree will also point this struct.
For your final question yes of course you could pass double pointer (in fact I followed this way in the definition of input_to_bst(&tree);).
An example of function input_to_bst definition could be:
void input_to_bst(treeptr* head,int number){
if((*head)==NULL){
(*head)=(treeptr)malloc(sizeof(struct tree));
(*head)->data=number;
(*head)->left=NULL;
(*head)->right=NULL;
}
else{
if(((*head)->data)>number) input_to_bst(&((*head)->left),number);
else (((*head)->data)<number) input_to_bst(&((*head)->right),number);
}
}
where we suppose that we have defined the structs:
struct tree{
int data;
struct tree* right;
struct tree* left;
};
typedef struct tree* treeptr;
Related
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.
I am trying to implement the insert operation of a binary search tree using C. Why does the following code show a Segmentation fault when trying to print the value of the left and right nodes of the root?
Please explain what caused this error exactly.
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node* left;
struct node* right;
};
struct node *root, *temp = NULL;
void insert(int data) {
struct node *newNode = (struct node*) malloc(sizeof(struct node));
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
if (root == NULL){
// if tree is empty insert the node as root
root = newNode;
}else {
// if the tree is not empty
temp = root;
while(temp != NULL) {
if(data <= root->data) {
temp = temp->left;
}
if(data > root->data) {
temp = temp->right;
}
}
temp = newNode;
}
}
int main() {
insert(7);
insert(4);
insert(8);
printf("\n\n------%d------", root->left->data);
printf("\n\n------%d------", root->right->data);
return 0;
}
The assignment temp = newNode only stores a pointer in the temp variable, not somewhere in the tree. So your tree's root node will never get any child. By consequence the main program is dereferencing a root->left pointer that is NULL, and this explains the error you get.
In order to really attach the new node at the right place in the tree, you need to modify a left or right member of some node. You can do this in several ways. One is to make temp a pointer-pointer, so that it will have the address of a left or right member. Then the assignment to *temp, will be an assignment to a node's left or right member, effectively extending the tree with that new node.
Here is the updated part of the code:
struct node **temp = &root;
while(*temp != NULL) {
if(data <= root->data) {
temp = &(*temp)->left;
}
if(data > root->data) {
temp = &(*temp)->right;
}
}
*temp = newNode;
okay you have a few issues here,
first of all, temp will point back to newNode, as you have not copied newNode's values to where temp is pointing now.
second and no less important, newNode is created within the scope of insert() - therefore, root will always remain null, as root points after execution of insert() to data wich no longer exists.
I have improved your code, and this definitely works as expected
hope it has helped.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node* left;
struct node* right;
}node;
node *root=NULL;
void insert(int data) {
node *temp = NULL;
if (root == NULL){
/* if tree is empty insert the node as root*/
root = malloc(sizeof(struct node));
root->data=data;
}else {
/*if the tree is not empty*/
temp = root;
while(temp->left!= NULL||temp->right!=NULL) {
if(data <= temp->data){
if(temp->left==NULL)
break;
else
temp = temp->left;
}
else if(data > temp->data){
if(temp->right==NULL)
break;
else
temp = temp->right;
}
}
if(data<= temp->data){
temp->left=malloc(sizeof(struct node));
(temp->left)->data=data;
}
else {
temp->right=malloc(sizeof(struct node));
(temp->right)->data=data;
}
/*temp=newNode;*/
}
}
int main() {
insert(7);
insert(4);
insert(8);
printf("\n\n------%d------", root->left->data);
printf("\n\n------%d------", root->right->data);
return 0;
}
I was making a program to make a binary search tree which takes input from the user.
I have deliberately shown two search functions in my code below.
Problem: The search function2 works correctly but the search function1 does not work correctly (when used after commenting the other each time).
Why is it so?
I tried doing the dry run and building the recursion stack, which works fine as per me. But somehow I think the search function 1 is not able to make that linking in the linked list to insert the element. That is the reason I am not getting the right output when I try to do the inorder traversal
Any help will be really appreciated!
#include <stdio.h>
#include <stdlib.h>
struct node{
int data;
struct node *left;
struct node *right;
};
struct node *root = NULL;
struct node *newNode(int data){
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->data = data;
temp->left = NULL;
temp->right = NULL;
return temp;
}
//SEARCH FUNCTION 1: this does not work correctly
void search(struct node *t,int data){
if(t){
if(data > t->data){
search(t->right,data);
}else{
search(t->left,data);
}
}else{
t = newNode(data);
}
}
//SEARCH FUNCTION 2: this works fine and inserts the element correctly
void search(struct node *t, int data){
if(data < t->data && t->left != NULL){
search(t->left, data);
}else if(data < t->data && t->left == NULL){
t->left = newNode(data);
}else if(data > t->data && t->right != NULL){
search(t->right,data);
}else{
t->right = newNode(data);
}
}
void insertNode(int data){
if(!root){
root = newNode(data);
return;
}
search(root, data);
}
void inorder(struct node *t){
if(t){
if(t->left){
inorder(t->left);
}
printf("%d ->", t->data);
if(t->right){
inorder(t->right);
}
}
}
int main(){
int step, data;
while(1){
printf("1. Insert element\n");
printf("2. Print tree\n");
scanf("%d",&step);
switch(step){
case 1: printf("enter element to be inserted\n");
scanf("%d",&data);
insertNode(data);
break;
case 2:inorder(root);
printf("\n");
break;
}
}
return 0;
}
The problem is that the statement t = newNode(data) assigns to a local variable, so the result is lost immediately after returning from the function.
In this case one solution is double indirection, as you don't just want to modify the thing a pointer points to, but the pointer itself.
void search(struct node **pt,int data)
{
struct node *t = *pt;
if (t) {
if (data > t->data) {
search(&t->right,data);
} else {
search(&t->left,data);
}
} else {
*pt = newNode(data);
}
}
1st search function:
void search(struct node *t,int data){
...
t = newNode(data);
}
but then in the 2nd search function you do:
void search(struct node *t, int data){
...
t->right = newNode(data);
}
which will remember the assignment, while the first will not, since when you are going to recurse, the changes will be lost.
You see in the 2nd case, you are assign what newNode() returns to data member of a struct that is a pointer, while the struct is passed a pointer in this function. However, in the 1st case, you assign the result in a struct that is passed by one pointer only. If a double pointer would be used, things would be differently.
I'm implementing an binary search tree but for some reasons I 'm not able to add a node
my: input was :
a.value = 5;
add_bst_node(&t,a);
mystructures:
typedef struct BST_node{
entity value;
struct BST_node* left;
struct BST_node* right;
}BST_node;
typedef struct BST_tree{
BST_node* root;
}BST_tree;
my code for add a node:
void add_bst_node2(BST_node* root,entity* e){
if(!root){
root = (BST_node*)malloc(sizeof(BST_node));
root->value = *e;
root->left = NULL;
root->right = NULL;
return;
}
else if(great_than(&root->value,e))
add_bst_node2(root->left,e);
else
add_bst_node2(root->right,e);
}
void add_bst_node(BST_tree* t,entity e){
add_bst_node2(t->root,&e);
printf("%d\n",t->root==NULL);
}
Someone can explayn why I'can't add a node?
Apart from not passing double pointer to BST_node (i.e. BST_node**) in add_bst_node2() as noted in the comments, you also didn't implement the function properly.
Your implementation never really adds a node, but instead in enters into infinite recursion.
Here you can find some clean theory about BST - http://www.zentut.com/c-tutorial/c-binary-search-tree/
Here is an untested correction of your code. Note that here we pass pointer to BST_tree instead of BST_node
void add_bst_node2(BST_tree* tree,entity* e){
if(!tree->root){
/* If the binary search tree is empty, we just create a root node */
tree->root = bst_create_node(e);
return;
}
int is_left = 0;
BST_node* current_node = tree->root;
BST_node* prev = NULL;
/* Traverse the tree until we find the proper position for the new node.
* The position is denoted by 'current_node'
*/
while(current_node != NULL) {
prev = current_node;
if(greater_than(¤t_node->value, e)) {
is_left = 1;
current_node = current_node->left;
} else {
is_left = 0;
current_node = current_node->right;
}
}
/* We finally know the position where we should add the new node */
if(is_left)
prev->left = bst_create_node(e);
else
prev->right = bst_create_node(e);
}
We introduce another function for creating and initializing a node...
BST_node *bst_create_node(entity *e)
{
BST_node *n = malloc(sizeof(BST_node));
n->value = *e;
n->left = NULL;
n->right = NULL;
return n;
}
And finally we change add_bst_node()
void add_bst_node(BST_tree* t,entity e){
add_bst_node2(t, &e);
printf("%d\n", t->root==NULL);
}
From what it seems, a is a struct BST_node and value is a variable in it. You have to either pass the value to the function and handle the node creation there, or pass the whole constructed node and just point to it from the existing tree.
first thing is that you put an unnecessary structure BST_tree.You do it in simple way like
struct node
{
int value;
node* left;
node* right;
};
struct node* root;
I suggest you try with this code
struct node* insert(struct node* r, int data)
{
if(r==NULL) // BST is not created created
{
r = (struct node*) malloc(sizeof(struct node)); // create a new node
r->value = data; // insert data to new node
// make left and right childs empty
r->left = NULL;
r->right = NULL;
}
// if the data is less than node value then we must put this in left sub-tree
else if(data < r->value){
r->left = insert(r->left, data);
}
// else this will be in the right subtree
else {
r->right = insert(r->right, data);
}
return r;
}`
`
I try to implement a binary tree in C with only one operation for the moment - insertion of a node to the tree. The problem I am facing is that I have a segmentation fault. The problem comes from the function insert, in the root = leaf instruction but I can't figure out how can I fix it. I've tried to write the function in a slightly different way. Instead of passing a leaf, I tried to pass a value to the insert function and to create a node of the binary tree inside the insert function. It didn't work out.
Can you please me tell me where I am wrong in my code? Thank you
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct binaryTree
{
int data;
struct binaryTree *left;
struct binaryTree *right;
};
//the seg fault comes from the function insert
void insert(struct binaryTree *leaf,struct binaryTree *root)
{
if(root == NULL)
{
//this is the problematic instruction
root = leaf;//construct the tree if it has not been constructed before
root->left = NULL;
root->right = NULL;
}
else if(leaf->data > root->data)
{
insert(leaf, root->right);
}
else if(leaf->data < root->data)
insert(leaf,root->left);
else
{
printf("The element is in the tree already.\n");
}
}
void print(struct binaryTree *root)
{
printf("-------Print--------\n");
if(root == NULL) return;
print(root->left);
printf("%d\n", root->data);
print(root->right);
}
void createNode(int value,struct binaryTree *node)
{
printf("-------CreateNode--------\n");
node = malloc(sizeof(struct binaryTree));
node->data = value;
node->left = NULL;
node->right = NULL;
}
void destroy(struct binaryTree *root)
{
if(root != NULL)
{
destroy(root->right);
destroy(root->left);
free(root);
}
}
int main()
{
struct binaryTree *root = NULL,*a,*b,*c;
createNode(42,a);
createNode(13,b);
createNode(20,c);
insert(a,root);
insert(b,root);
insert(c,root);
print(root);
destroy(root);
return 0;
}
The problem:
At the beginning of main(), root is NULL and a is untitialised.
The problem is that createNode(42,a); will create and allocate a node, but it's address will be lost. Only the local parameter node will be set by this function and lost forever as soon as it returns. This value will not be copied to a, which hence remain unitialized.
Then you try to instert(a, root): a is still an unitialised pointer and root is still NULL. The first thing that will hapen in insert() is that you'll copy the unitialised pointer into root, and then you dereference this invalid pointer by trying to set some structure members to NULL. That causes the segmentation fault !
How to solve it:
Make sure that createNode() returns the value:
struct binaryTree *createNode(int value)
{
printf("-------CreateNode--------\n");
struct binaryTree *node = malloc(sizeof(struct binaryTree));
node->data = value;
node->left = NULL;
node->right = NULL;
return node;
}
and change min accordingly:
a = createNode (42);
...
You then have a similar problem in insert(), with the root argument. You could here do a similar technique, by rewriting your function:
struct binaryTree *insert(struct binaryTree *leaf,struct binaryTree *root) {...}
But it requries a little bit more gynmnastics as with createNode().
I propose you therefore another alternative, passing as argument a pointer to a root pointer: this pemits you to change the value of the root poniter
void insert(struct binaryTree *leaf,struct binaryTree **root) // pointer to pointer
{
if(*root == NULL)
{
//this is the problematic instruction
*root = leaf;//construct the tree if it has not been constructed before
(*root)->left = NULL;
(*root)->right = NULL;
}
else if(leaf->data > (*root)->data)
{
insert(leaf, &root->right);
}
else if(leaf->data < (*root)->data)
insert(leaf,&root->left);
else
{
printf("The element is in the tree already.\n");
}
}
In main you'd then call it:
insert(a,&root);