I've been trying to implement a simple binary search tree in C just as an exercise. I can insert elements into the tree, but at certain points (I haven't been able to figure out where) I'm getting a segmentation fault.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
struct node {
struct node *left;
struct node *right;
int key;
};
void insert(struct node *treeNode, int key);
void outputTree(struct node *root);
int main(){
//Store how many numbers the user will enter
printf("How many numbers will you enter? > ");
int numNumbers;
scanf("%d", &numNumbers);
//Create a root node
struct node root;
root.key = -1; //-1 Means the root node has not yet been set
root.right = NULL;
root.left = NULL;
//Now iterate numNumbers times
int i;
for(i = 1; i <= numNumbers; ++i){
int input;
scanf("%d", &input);
insert(&root, input);
}
outputTree(&root);
return 0;
}
void insert(struct node *treeNode, int key){
//First check if the node is the root node
if((*treeNode).key == -1){
printf("Root node is not set\n");
(*treeNode).key = key; //If the root node hasn't been initialised
}
else {
//Create a child node containing the key
struct node childNode;
childNode.key = key;
childNode.left = NULL;
childNode.right = NULL;
//If less than, go to the left, otherwise go right
if(key < (*treeNode).key){
if((*treeNode).left != NULL){
printf("Left node is not null, traversing\n");
insert((*treeNode).left, key);
}
else {
printf("Left node is null, creating new child\n");
(*treeNode).left = &childNode;
}
}
else {
//Check if right child is null
if((*treeNode).right != NULL){
printf("Right node is not null, traversing...\n");
insert((*treeNode).right, key);
}
else {
printf("Right node is null, creating new child\n");
(*treeNode).right = &childNode;
}
}
}
}
void outputTree(struct node *root){
//Traverse left
if((*root).left != NULL){
outputTree((*root).left);
}
printf("%d\n", (*root).key);
if((*root).right != NULL){
outputTree((*root).right);
}
}
As of writing this question, I've just had the thought, are the child nodes being created on the stack, so when the recursive calls return, the references in the tree are pointing to a struct that no longer exists?
What is wrong here?
Thank you
You create childs node on the stack by static allocation. When the insert method is finished, the child reference become invalid.
You should use dynamic allocation with malloc.
struct node *new_node(int key, struct node *left, struct node *right) {
struct node *this = malloc(sizeof *this);
this->key = key;
this->left = left;
this->right = right;
return this;
}
don't forget to free all of your allocations with the free function.
edit :
so to create the root just use
struct node *root = new_node(-1, NULL, NULL);
Related
I have previously posted about this same topic. I am self-learning data structures using MIT Open Courseware. I'm doing the 6.S096-Introduction to C/C++ course and attempting the fourth assignment.
It is based on binary search trees and I gave it a try. I wanted to print the values for debugging but kept getting different executions each time.
One time, the cycle doesn't complete and the other time, it goes on to infinity. The debugging block also relates to the other function(find_node_data) I have to complete. So if I can figure what's wrong here, I can easily finish the find_node_data. I have commented a few things to see if it affects anything. What am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int node_id;
int data;
struct node* left;
struct node* right;
}node;
///*** DO NOT CHANGE ANY FUNCTION DEFINITIONS ***///
// Declare the tree modification functions below...
node* newNode(int data,int node_id){
node* new_node = (node*) malloc(sizeof(node));
new_node->data = data;
new_node->node_id= node_id;
new_node->right= new_node->left=NULL;
return new_node;
}
node* insert_node(node* root, int node_id, int data) {
if(root==NULL)
return newNode(data,node_id);
else{
node* cur;
if(node_id<root->node_id){
cur=insert_node(root->left,data,node_id);
root->left=cur;
}
else if(node_id>root->node_id){
cur=insert_node(root->right,data,node_id);
root->right=cur;
}
}
return root;
}
// Find the node with node_id, and return its data
/*int find_node_data(node* root, int node_id) {
node* current;
for( current = root->; current->next!=NULL;
current= current->next){
if(current->data == data) return current;
}
return NULL;
}
*/
int main() {
/*
Insert your test code here. Try inserting nodes then searching for them.
When we grade, we will overwrite your main function with our own sequence of
insertions and deletions to test your implementation. If you change the
argument or return types of the binary tree functions, our grading code
won't work!
*/
int T,data,node_id;
printf("Print yo cases");
scanf("%d", &T);
node* root = NULL;
while(T-->0){
printf("Type yo numnums no. %d:",T);
scanf("%d %d",&data,&node_id);
root=insert_node(root,data,node_id);
}
node *lol;
node *king;
for(lol=root;lol->left!=NULL;lol=lol->left){
//for(king=root;king->right!=NULL;king=king->right){
printf("executed!\n");
printf("%d ",lol->node_id);//,king->node_id);
//}
}
return 0;
}
To find the node_data you can use recursion to find the node.
node* find_node_data(node *root, int node_id) {
if (root == NULL)
return NULL;
else if (root->node_id == node_id)
return root;
else {
node *left = find_node_data(root->left, node_id);
return left? left: find_node_data(root->right, node_id);
}
}
And then get the data for the node e.g. get the data for node with node_id 42:
printf("node data %d", find_node_data(root, 42)->data);
Full program below (I can't guarantee its correctness but maybe you can?)
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int node_id;
int data;
struct node *left;
struct node *right;
} node;
///*** DO NOT CHANGE ANY FUNCTION DEFINITIONS ***///
// Declare the tree modification functions below...
node *newNode(int data, int node_id) {
node *new_node = (node *) malloc(sizeof(node));
new_node->data = data;
new_node->node_id = node_id;
new_node->right = new_node->left = NULL;
return new_node;
}
node *insert_node(node *root, int data, int node_id) {
if (root == NULL)
return newNode(data, node_id);
else {
node *cur;
if (node_id < root->node_id) {
cur = insert_node(root->left, data, node_id);
root->left = cur;
}
else if (node_id > root->node_id) {
cur = insert_node(root->right, data, node_id);
root->right = cur;
}
}
return root;
}
// Find the node with node_id, and return its data
/*
int find_node_data_old(node *root, int node_id) {
node *current;
for (current = root->; current->next != NULL;
current = current->next) {
if (current->data == data) return current;
}
return NULL;
}*/
node* find_node_data(node *root, int node_id) {
if (root == NULL)
return NULL;
else if (root->node_id == node_id)
return root;
else {
node *left = find_node_data(root->left, node_id);
return left? left: find_node_data(root->right, node_id);
}
}
void print(node *np) {
if (np) {
print(np->left);
printf("(%d, %d)", np->node_id, np->data);
print(np->right);
}
}
int main() {
/*
Insert your test code here. Try inserting nodes then searching for them.
When we grade, we will overwrite your main function with our own sequence of
insertions and deletions to test your implementation. If you change the
argument or return types of the binary tree functions, our grading code
won't work!
*/
int T, data, node_id;
printf("Print yo cases");
scanf("%d", &T);
node *root = NULL;
while (T-- > 0) {
printf("Type yo numnums no. %d:", T);
scanf("%d %d", &data, &node_id);
root = insert_node(root, data, node_id);
}
node *lol;
node *king;
for (lol = root; lol->left != NULL; lol = lol->left) {
//for(king=root;king->right!=NULL;king=king->right){
printf("executed!\n");
printf("%d ", lol->node_id);//,king->node_id);
//}
}
print(root);
printf("\n");
printf("node data %d", find_node_data(root, 42)->data);
return 0;
}
Test
Print yo cases3
Type yo numnums no. 2:22 42
Type yo numnums no. 1:21 41
Type yo numnums no. 0:20 40
executed!
42 executed!
41 (40, 20)(41, 21)(42, 22)
node data 22
You may also use Jonathan Leffler's improved recursion to find the node:
node *find_node_data2(node *root, int node_id) {
if (root == NULL)
return NULL;
else if (root->node_id == node_id)
return root;
else if (root->node_id > node_id)
return find_node_data(root->left, node_id);
else
return find_node_data(root->right, node_id);
}
Both functions return the correct values as seen in the second test.
int main() {
/*
Insert your test code here. Try inserting nodes then searching for them.
When we grade, we will overwrite your main function with our own sequence of
insertions and deletions to test your implementation. If you change the
argument or return types of the binary tree functions, our grading code
won't work!
*/
int T, data, node_id;
printf("Print yo cases");
scanf("%d", &T);
node *root = NULL;
while (T-- > 0) {
printf("Type yo numnums no. %d:", T);
scanf("%d %d", &data, &node_id);
root = insert_node(root, data, node_id);
}
node *lol;
node *king;
for (lol = root; lol->left != NULL; lol = lol->left) {
//for(king=root;king->right!=NULL;king=king->right){
printf("executed!\n");
printf("%d ", lol->node_id);//,king->node_id);
//}
}
print(root);
printf("\n");
printf("node data %d\n", find_node_data(root, 42)->data);
printf("node data find_node_data2 %d", find_node_data2(root, 42)->data);
return 0;
}
Test 2
Print yo cases3
Type yo numnums no. 2:11 12
Type yo numnums no. 1:13 14
Type yo numnums no. 0:20 42
(12, 11)(14, 13)(42, 20)
node data 20
node data find_node_data2 20
I'm trying to implement a binary search tree that holds an inventory of ordered stock. The stocked item attributes are stored in nodes as such:
typedef struct item item_t;
struct item{
char name;
int price;
int quantity;
item_t *left;
item_t *right;
};
The idea is to prompt a user to enter the above attributes, and then add the entered item to a node. This is what I've written so far:
item_t *root = NULL;
item_t *current_leaf = NULL;
void prompt_user(){
/*
In here contains the code that prompts the user for the item attributes
and stores it in a variable called input
*/
insert_node(input);
}
void insert_node(char *input){
/*If tree doesnt have a root...*/
if (root == NULL){
/*Create one...*/
*root = create_node(input);
}
else{
item_t *cursor = root;
item_t *prev = NULL;
int is_left = 0;
int comparison;
while(cursor != NULL){
/*comparison will be 1 is the key of input is less than the key
of the cursor, and 2 otherwise...*/
comparison = compare(input, cursor);
prev = cursor;
if(comparison == 1){
is_left = 1;
cursor = cursor->left;
}
else if (comparison == 2){
is_left = 0;
cursor = cursor->right;
}
}
if(is_left){
*prev->left = create_node(input);
current_leaf = prev->left;
}
else{
*prev->right = create_node(input);
current_leaf = prev->right;
}
}
}
item_t create_node(char *input){
item_t *new_node = (item_t*)malloc(sizeof(item_t));
if (new_node == NULL){
printf("Out of memory. Shutting down.\n");
exit(EXIT_FAILURE);
}
/*Add data to the node...*/
update_item(input, new_node);
new_node->left = NULL;
new_node->right = NULL;
current_leaf = new_node;
return *new_node;
}
I want root to always be pointing to the first item ever entered, and current_leaf to be pointing to the last item processed. compare returns 1 if the item being processed (input) is less than the last processed item (current_leaf). update_item is what sets the data for the new nodes (leaves).
The above isn't fully complete, but it's what I'm up to at the moment. I'm struggling to work out how to write add_node and how to keep current_leaf updated correctly.
EDIT: revised my code
It is an example of BST. Structure of the tree is:
typedef struct node{
int data;
struct node *left, *right;
}node;
Letting root global is not a good idea, so it is better to declare it inside main() and the insert() will be called from main like this:
int main()
{
int n,data;
node *root=NULL;
printf("How many elements? ");
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&data);
insert(&root,data);
}
inorder(root);
return 0;
}
This is the code for insertion and traversing a binary tree-
void insert(node **root, int data)
{
node *n1,*temp;
n1=(node *)malloc(sizeof(node));
n1->data=data;
n1->left=n1->right=NULL;
if(!(*root))
{
(*root)=n1;
//printf("Node inserted\n");
return;
}
temp=*root;
while(temp!=NULL)
{
if(temp->data<temp->data)
{
//printf("To the right");
if(temp->right==NULL)
{
temp->right=n1;
break;
}
else
temp=temp->right;
}
else if(temp->data>=n1->data)
{
if(temp->left==NULL)
{
temp->left=n1;
break;
}
else
temp=temp->left;
}
}
//printf("Inserted\n");
}
void inorder(node *root)
{
if(root==NULL)
return;
inorder(root->left);
printf("item: %d",root->data);
inorder(root->right);
}
The searching will be same almost same logic as insert, please develop it yourself.
I am trying to create a binary tree and i am new to data structure.
What i have to do is:
(1) Take the size of tree (total number of nodes) at terminal.
(2) Then up to size read nodes from the user at terminal
(3) Then create Binary search tree.
Note: I have to pass the node by reference only` in the function call(No other options).
It compiles without error but i guess there is any logical problem.It gives segmentation fault when i try to insert second node in for loop (for first it works fine) but compile without errors .I am not able to predict it's due to which line of code?
When I do:
How many nodes are to be inserted ?
5
enter the nodes
1 //I am not able to add more nodes
Segmentation fault (core dumped)
Answer in any language c/c++ or even algorithm are welcome.
My code to do so is :
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
struct node
{
int freq;
struct node * left, * right;
};
typedef struct node node;
/////////////////////////////////////////////////////////////Function definitions //////////////////////////////////////////////////
insert_first_node(int data, node * * Node)
{
node * temp1 ;
temp1 = Node;
temp1= (node * ) malloc(sizeof(node));
temp1 -> freq = data;
temp1 -> left = NULL;
temp1 -> right = NULL;
}
////////////////////////////////////////////////////////////////////
insert_beginning(int data, node * * Node)
{
root = * Node;
root = (node * ) malloc(sizeof(node));;
if (root ==NULL)
{
insert_first_node(data, & root);
}
if (data <= root -> freq)
{
insert_beginning(data, & root -> left);
} else
{
insert_beginning(data, & root -> right);
}
*Node = root;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
main()
{
int i, size, data;
node * head;
head = NULL;
printf("How many nodes are to be inserted ?\n");
scanf("%d", & size);
for (i = 1; i <= size; i++)
{
printf("enter the nodes \n");
scanf("%d", & data);
insert_beginning(data, & head);
}
}
I would write it like this (although I wouldn't necessarily use recursion, but maybe you are supposed to...):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node
{
int freq;
struct Node *left;
struct Node *right;
} Node;
///////////////////////////////////////////////////////////
// Function definitions //
///////////////////////////////////////////////////////////
int insert_leaf_node(int freq, Node **parent_ptr)
{
Node *node;
if ((node = malloc(sizeof *node)) == NULL)
return -1;
node->freq = freq;
node->left = NULL;
node->right = NULL;
*parent_ptr = node;
return 0;
}
///////////////////////////////////////////////////////////
int insert_node(int freq, Node **parent_ptr)
{
Node *node = *parent_ptr;
if (node == NULL) {
return insert_leaf_node(freq, parent_ptr);
}
else if (freq <= node->freq) {
return insert_node(freq, &node->left);
}
else {
return insert_node(freq, &node->right);
}
}
///////////////////////////////////////////////////////////
int main()
{
int i, size, freq;
Node *root = NULL;
printf("How many nodes are to be inserted ?\n");
scanf("%d", &size);
for (i = 0; i < size; i++) {
printf("enter the freq of node %d\n", i+1);
scanf("%d", &freq);
insert_node(freq, &root);
}
return 0;
}
And here's how I would write insert_node without recursion:
int insert_node(int freq, Node **parent_ptr)
{
Node *node;
while ((node = *parent_ptr) != NULL) {
parent_ptr = (freq <= node->freq) ? &node->left : &node->right;
}
return insert_leaf_node(freq, parent_ptr);
}
You are getting segmentation fault starting from first input only. Let me clear the reason for that.
In insert_beginning function, first line is root = * Node;. Here *Node is NULL already. So root would have NULL value also. You expected that root also points to same address as *Node but this is not the case as *Node is pointing to nothing, so root and *Node are still unrelated. Now you have allocated the memory to root in previous line, but now you have assigned NULL to root. So previous assigned address to root is lost. So that is the leak memory, Dalibor is talking about.
Lets go ahead.
Now root==NULL is checked, which is true, so insert_first_node is called. There is temp1=Node, which is syntactically wrong. I think you intended temp1 = *Node. But still that is wrong as *Node is NULL, so would be temp1. Now you are assigning value to NULL object. So next line gives segmentation fault.
The working code can be
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
struct node
{
int freq;
struct node * left, * right;
};
typedef struct node node;
/////////////////////////////////////////////////////////////Function definitions //////////////////////////////////////////////////
void insert_first_node(int data, node * * Node,int direction)
{
node * temp1 = (node * ) malloc(sizeof(node));
temp1 -> freq = data;
temp1 -> left = NULL;
temp1 -> right = NULL;
if(*Node == NULL)
*Node = temp1;
else if(direction == 1)
(*Node)->right = temp1;
else
(*Node)->left = temp1;
}
////////////////////////////////////////////////////////////////////
void insert_beginning(int data, node * * Node)
{
node *root;
root = * Node;
if (root == NULL)
{
insert_first_node(data,Node,0);
return;
}
if (data <= root -> freq)
{
if(root->left == NULL)
insert_first_node(data,&root,0);
else
insert_beginning(data,&root->left);
} else
{
if(root->right == NULL)
insert_first_node(data,&root,1);
else
insert_beginning(data,&root->right);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
main()
{
int i, size, data;
node * head;
head = NULL;
printf("How many nodes are to be inserted ?\n");
scanf("%d", & size);
for (i = 1; i <= size; i++)
{
printf("enter the nodes \n");
scanf("%d", & data);
insert_beginning(data, & head);
}
}
It seg-faults during the insertion of your first node. If it was during the second insert, you would see the message "enter the nodes" twice.
Now to the reason. In the function insert_beginning, the first if statement does not compare root to NULL, but sets it to NULL. Since NULL is treated as false, the code inside the if is not evaluated and the execution moves to the second if statement. In it, you're trying to access freq field of root, which is set to NULL from the first if statement. So you are trying to dereference NULL pointer, which leads to the seg-fault.
Here is the node of Linked List:
struct Node {
char data;
struct Node *next;
int pindex; //this is the first index position in parent[] which is null, next element goes here
int cindex; //this one for child array
char parent[50];
char child[50];
};
This is how i am creating each node.
struct Node *createNode(struct Node *node, char nodeData) {
if(root == NULL) {
int i=0;
node= malloc(sizeof(struct Node));
node->data = nodeData;
while(i<50) {
node->parent[i]= '\0';
node->child[i]= '\0';
i++;
}
node->pindex=0;
node->cindex=0;
node->next= malloc(sizeof(struct Node));
root=node;
return node;
}
else if (node->data == 0) {
int j=0;
node->data = nodeData;
while (j<50) {
node->parent[j]= '\0';
node->child[j]= '\0';
j++;
}
node->pindex=0;
node->cindex=0;
node->next= malloc(sizeof(struct Node));
return node;
}
else
return createNode(node->next, nodeData);
}
Here is my code where i am updating the values of the parent and child arrays in a particular node.
void insert(char a, char b) {
struct Node *pNode, *cNode;
if (hasNode(root,a)) //check if Node with node->data ='a' exists else create it
pNode= getNode(root,a);
else {
pNode= createNode(root,a);
//addToFirst(one); No need as we already have list of all elements
}
if (hasNode(root, b))
cNode= getNode(root,b);
else
cNode= createNode(root, b);
pNode->child[(pNode->cindex)] = b; //insert a char into child array of parent node
pNode->cindex++;
cNode->parent[(cNode->pindex)]= a; // insert char into child array of parent node
cNode->pindex++;
}
Problem is with the following section
pNode->child[(pNode->cindex)] = b; //insert a char into child array of parent node
pNode->cindex++;
cNode->parent[(cNode->pindex)]= a; // insert char into child array of parent node
cNode->pindex++;
as any element is inserted into the parent[] of cNode, its child[] is gone from the memory. And if i insert later anything into child, its working.
Following is the screenshot i took for this linked list, that should help. The child array is missing from the data root->next node
[Screenshot of the data structure]
Here is a program it is working
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next, *prev;
};
struct node *root = NULL;
void push(int);
void pop(void);
struct node *create_node(int);
void travel(void);
int main()
{
int i, j, choice, count;
printf("enter choice\n");
scanf("%d", &choice);
count = 0;
while (choice == 1) {
printf("enter a data element");
scanf("%d", &j);
if (count == 0) {
root = (struct node *)malloc(sizeof(struct node));
root->next = NULL;
root->data = j;
} else
push(j);
count++;
printf("enter choice\n");
scanf("%d", &choice);
}
printf("the link list is \n");
//travel function to be created
travel();
}
void push(int data)
{
struct node *t1;
t1 = root;
while (t1->next != NULL) {
t1 = t1->next;
}
t1->next = create_node(data);
}
void pop()
{
}
void travel(void)
{
struct node *t1;
t1 = root;
while (t1->next != NULL) {
printf("%d ", t1->data);
t1 = t1->next;
}
printf("%d ", t1->data);
}
struct node *create_node(int data)
{
struct node *p = (struct node *)malloc(sizeof(struct node));
p->data = data;
p->next = NULL;
p->prev = NULL;
return p;
}
the above program is fully working,I have used a global pointer root.
My problem is if I do not want to use a global pointer root here then how do I maintain
that list because each time I will have to return the root of list in my push pop functions
is there any other way to achieve the same?
The simplest way to achieve this is to pass a pointer to the root node pointer to each of your functions:
void push(struct node **root, int data) { ... }
void pop(struct node **root) { ... }
void travel(struct node *root) { ... }
So, in your main function you might declare a local variable to hold the root pointer:
struct node *root = NULL;
and then when you call push, for example, you pass the address of the root poiner:
push(&root, data);
I strongly recommend that you fix your push and travel functions so that they are robust to the root pointer being NULL. This was discussed in a previous question of yours and you should heed the advice.
If you did that then you could get rid of the test for count being zero and the associated special case code. You would then replace this:
if (count == 0) {
root = (struct node *)malloc(sizeof(struct node));
root->next = NULL;
root->data = j;
} else
push(&root, j);
with this:
push(&root, j);
To drive home the message, your new push would look like this:
void push(struct node **root, int data)
{
if (*root == NULL)
*root = create_node(data);
else
{
struct node *last = *root;
while (last->next != NULL) {
last = last->next;
}
last->next = create_node(data);
}
}
You would need to modify travel also to include a check for the root node being NULL. I will leave that as an exercise for you.
Maintaining both head and tail pointers could be a better approach since it would avoid so many list traversals.