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.
Related
I need to go through a list linked by the middle of a function with a parameter that is a triple pointer, by means of a recursive void function.
The program is as follows
typedef struct node
{
int data;
struct node* next;
}Node;
void insert(Node** first,int d){
Node* new= createNode(d);
new->next= *first;
*first=new;
}
Node* createNode(int d){
Node* new= (Node*)malloc(sizeof(Node));
new->data= d;
new->next=NULL;
return new;
}
void printList(Node***p)
{
Node**temp = *p;
if(temp == NULL)
return;
else
{
printf("\nValue: %d", (*temp)->data);
*temp = (*temp)->next;
printList(&temp);
}
}
int main()
{
Node *first = NULL;
int n =10;
while(n>0){
insert(&first,n);
n=n-1;
}
Nodo **ptr_first= &first;
printList(&ptr_first);
return 0;
}
The function prints all the values, but the program hangs and returns a negative value. What is wrong with this implementation?
PD: The use of the triple pointer is only for teaching purposes
Your recursion termination condition is wrong.
You have tho change if(temp == NULL) to if(*temp == NULL), since *temp is pointing to the element and not temp.
I also think that it is not good for teaching if you use triple pointers since they are not necessary here.
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;
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);
I wrote the following code for creation of Binary Search Tree, but when the creation function is called and it tries to call the insertNode(...) for the 1st time the program hangs up. Following is the code :
struct BstNode{
int value;
struct BstNode* left;
struct BstNode* right;
};
struct BstNode *root;
struct BstNode* insertNode(struct BstNode* root, int data){
if(data <= root->value)
root->left = insertNode(root->left, data);
else
root->right = insertNode(root->right, data);
printf("%d ",root->value);
return root;
}
void create(struct BstNode* root){
int data;
if(root == NULL){
//create the root node
printf("\nInside create");
root = (struct BstNode*) malloc(sizeof(struct BstNode));
printf("\nData :: ");
scanf("%d",&data);
root->value = data;
root->left = NULL;
root->right = NULL;
}
else{
printf("\nCalling insertNode()");
printf("\nData :: ");
scanf("%d",&data);
root = insertNode(root, data); // The program hangs up here : the very first time this line is executed
printf("\nCalled insert");
}
}
int main(){
root = NULL;
int i;
for(i=0;i<5;i++){
create(root);
printf("%d ",root->value); // For checking the value
}
return 0;
}
Could anybody point out my mistake. Any suggestion(s) is helpful.
Could anybody point out my mistake.
The main problem is that createNode modifies a local copy of root. The global variable root is never modified, and remains set to NULL.
Any suggestion(s) is helpful.
Avoid using global variables. Move root to be a local variable in main.
Change the signature and purpose of create so that it simply creates a node, and nothing else.
Don't cast the results of malloc. See Specifically, what's dangerous about casting the result of malloc?
Use insertNode instead of create in main. Call create from insertNode at the right place.
Add a function that prints the contents of the tree.
While testing the code, use random numbers instead of user entered data.
Allow the flexibility of creating more than 5 nodes by using a command line argument.
Here's my suggestion for the program:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct BstNode{
int value;
struct BstNode* left;
struct BstNode* right;
};
struct BstNode* create(int data){
printf("Creating a node with value: %d\n", data);
struct BstNode* node = malloc(sizeof(*node));
node->value = data;
node->left = NULL;
node->right = NULL;
return node;
}
struct BstNode* insertNode(struct BstNode* root, int data){
if ( root == NULL )
{
return create(data);
}
if(data <= root->value)
root->left = insertNode(root->left, data);
else
root->right = insertNode(root->right, data);
return root;
}
void print(struct BstNode* node, int indent, char const* nodeName)
{
if ( node == NULL )
{
return;
}
for (int i = 0; i < indent; ++i )
{
printf(" ");
}
printf("%s: %d\n", nodeName, node->value);
print(node->left, indent+1, "left");
print(node->right, indent+1, "right");
}
int main(int argc, char** argv){
struct BstNode *root = NULL;
int i;
int data;
int num = 5;
if ( argc > 1 )
num = atoi(argv[1]);
srand(time(NULL));
for(i=0;i<num;i++){
data = rand()%10000;
root = insertNode(root, data);
}
printf("\n");
print(root, 0, "root");
return 0;
}
The algorithm for inserting in such tree is (insert(node, value)) :
if node is NULL allocate a node, set left/right to NULL (it is a leaf), set value to value, return the allocated node
else if value < node->value: node->left = insert(node->left, value)
else : node->right = insert(node->right, value)
return node (so that we have homogeneous code)
Inserting from let say your main is the same: root = insert(root, val).
Rather than returning the value you can also pass a pointer to your pointer (&root) but then you'll have to deal with dereferencing it in the function. You don't seems to be very familiar with pointers, you really should read more about that if you plan to play with such structures.
Note also that your printf in your main function is not useful: in that kind of trees the root value will always be the 1st inserted value (or you would have to perform shifts in the tree to equilibrate the branches, but this is an other problem).
Printing a btree implies a recursive function too, and you have to choose how to print it (deep-first, sorted…). Example: if node is NULL return; call yourself on left; print value; call yourself on right → will print content sorted in small-to-large order.
The function insertNode has infinite recursion which causes your program to crash.
More specifically
struct BstNode* insertNode(struct BstNode* root, int data){
if(data <= root->value)
root->left = insertNode(root->left, data);
else
root->right = insertNode(root->right, data);
printf("%d ",root->value);
return root;
You go in function and check if(data <= root->value). In both cases (true and false) you call insertNode function again which then call for insertNode again and again - you will never got to the return statement. Recursive function need to have base case which returns some value without calling itself again.
thisFunction()
if (base case)
return value;
else
return thisFunction()
In case of binary search trees, the base case is when you the key(data) you are inserting is A) inserted key is bigger than current node AND current node's right child is leaf (null) or B) inserted key is smaller (or equal depending on how you want to resolve ties) than your current node AND current node's left child is null .(data > cur->data && cur->right == NIL) or (data < cur->data && cur->left == NIL). Should you hit one of these cases just make the new node right child or left child of the current node.
I am implementing the binary search tree with some operations ( new node, search, insert and display).
It results in following warning.
binarytree.c:70: warning: assignment makes pointer from integer without a cast
binarytree.c:72: warning: assignment makes pointer from integer without a cast
binarytree.c:73: warning: return makes integer from pointer without a cast
binarytree.c: At top level:
binarytree.c:78: warning: conflicting types for ‘printInoder’
binarytree.c:47: warning: previous implicit declaration of ‘printInoder’ was here
binarytree.c: In function ‘NewNode’:
binarytree.c:122: warning: return makes pointer from integer without a cast
Undefined symbols for architecture x86_64:
"_newNode", referenced from:
_main in cckg2mll.o
_insert in cckg2mll.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
You will see my source code here below but I wish to hear your suggestions. I fully understand the Binary trees functions but I think it is not related to any algorithm but it is a programming problem.
Source Code
It is really long code but I cannot reduce it for your guys.
#include <stdlib.h>
#include <stdio.h>
#define false 0
#define true 1
struct Node
{
int data;
struct Node *left, *right;
}*node,*root;
int main(void)
{
root = (struct Node *)malloc(sizeof(struct Node));
int option = 1;
int choice,value,target,newvalue;
while(option)
{
printf("Enter your choice \n");
scanf("%d\n",&choice);
switch(choice)
{
case 1:
printf("Enter the a new value\n");
insert(root,value);
scanf("%d\n",&value);
break;
case 2:
printf("Enter the traget \n");
scanf("%d\n",&target);
lookup(root,target);
break;
case 3:
printf("Enter the new node \n");
scanf("%d\n",&newvalue);
newNode();
break;
case 4:
printInoder();
break;
}
printf("Enter 0 or 1\n");
scanf("%d\n",&option);
}
}
int insert(struct Node *node ,int data)
{
// 1. If the tree is empty, return a new, single node
node = (struct Node *)malloc(sizeof(struct Node));
if (node == NULL)
{
return(newNode(data));
}
else
{
// 2. Otherwise, recur down the tree
if (data <= node->data)
node->left = insert(node->left, data);
else
node->right = insert(node->right, data);
return(node); // return the (unchanged) node pointer
}
}
void printInoder()
{
root = (struct Node *)malloc(sizeof(struct Node));
if (root != NULL)
{
printInoder(root->left);
printf("%d ",root->data);
printInoder (root->right);
}
}
int lookup(struct Node *node, int target)
{
node = (struct Node *)malloc(sizeof(struct Node));
// 1. Base case == empty tree
// in that case, the target is not found so return false
if (node == NULL)
{
return(false);
}
else
{
// 2. see if found here
if (target == node->data) return(true);
else
{
// 3. otherwise recur down the correct subtree
if (target < node->data)
return(lookup(node->left, target));
else return(lookup(node->right, target));
}
}
}
struct Node *NewNode(int x)
{
node =(struct Node *)malloc(sizeof(struct Node)); // "new" is like "malloc"
node->data = x;
node->left = NULL;
node->right = NULL;
return(x);
}
So, the biggest issue is that you ignore data types. insert function returns int but whenever you assign its return value or even return something inside this function, the variables you use are pointers instead - so change return type of insert to struct Node *node.
Also, in case 4 part, you use function printInoder which is declared and defined after calling it (below main function) so that is why it warns you that you should at least declare this function before main.
Finally, inside insert function, you call newNode but this function is called NewNode and it is also declared and defined below main.
You called the following function using newNode not NewNode. Also, move the * off of the NewNode part.
struct Node *NewNode(int x)
{
node =(struct Node *)malloc(sizeof(struct Node)); // "new" is like "malloc"
node->data = x;
node->left = NULL;
node->right = NULL;
return(x);
}
Your insert function returns a node pointer but is declared with an int return type.
Also, you need to declare functions above where they are called the first time. add a declaration statement to the top of the page for your functions to work.
return_type function_name(params);
Finally, rename your function to printInOrder() instead of printInoder()
Your code has many errors.
I've edited it a bit:
#include <stdlib.h>
#include <stdio.h>
#define false 0
#define true 1
struct Node
{
int data;
struct Node *left, *right;
};
void insert(struct Node **node, int data);
int lookup(struct Node *node, int target);
void printInoder(struct Node *root);
struct Node *NewNode(int x);
int main(void)
{
struct Node *root = NULL;
int option = 1;
int choice, value, target;
while (option)
{
choice = value = target = 0;
printf("Enter your choice \n");
scanf("%d", &choice);
switch (choice)
{
case 1:
printf("Enter the a new value\n");
scanf("%d", &value);
insert(&root, value);
break;
case 2:
printf("Enter the traget \n");
scanf("%d", &target);
printf("%d\n", lookup(root, target));
break;
case 3:
printf("Printing\n");
printInoder(root);
printf("\n");
break;
}
printf("Enter 0 or 1\n");
scanf("%d", &option);
}
return 0;
}
void insert(struct Node **root, int data)
{
// 1. If the tree is empty, return a new, single node
struct Node *node = NewNode(data);
if (*root == NULL)
{
*root = node;
return;
}
// 2. Otherwise, recur down the tree
if (data <= (*root)->data)
insert(&(*root)->left, data);
else
insert(&(*root)->right, data);
}
void printInoder(struct Node *root)
{
if (root == NULL) return;
printInoder(root->left);
printf("%d ", root->data);
printInoder(root->right);
}
int lookup(struct Node *root, int target)
{
// 1. Base case == empty tree
// in that case, the target is not found so return false
if (root == NULL)
{
return(false);
}
// 2. see if found here
if (target == root->data) return(true);
// 3. otherwise recur down the correct subtree
if (target < root->data)
return(lookup(root->left, target));
else return(lookup(root->right, target));
}
struct Node *NewNode(int x)
{
struct Node *node= malloc(sizeof *node);
node->data = x;
node->left = NULL;
node->right = NULL;
return node;
}
Try it, and take a look at the changes in the code.