When I call insert(element) function and add element, it gives an error as programme has stopped working.
It gives an error when i add 3rd element in left of root or add an element in right side of root.
please help to solve it.
void insert(int iElement){
if(sRoot==NULL){ //Initially sRoot is NULL
sRoot=(struct Node*)malloc(sizeof(struct Node));
sRoot->iData=iElement;
sRoot->sLeft=NULL;
sRoot->sRight=NULL;
}
else{
struct Node *current=(struct Node*)malloc(sizeof(struct Node));
current->iData=iElement;
current->sLeft=NULL;
current->sRight=NULL;
struct Node *parent;
struct Node *temp;
parent=sRoot;
while(parent!=NULL){
temp=parent;
if(iElement>parent->iData){
parent=parent->sRight;
}
if(iElement<parent->iData){
parent=parent->sLeft;
}
}
if(iElement<temp->iData)
temp->sLeft=current;
else
temp->sRight=current;
}
}
There are two bugs in the function the first is that in the loop there are used two if statements instead of if-else if statements.
while(parent!=NULL){
temp=parent;
if(iElement>parent->iData){
parent=parent->sRight;
}
if(iElement<parent->iData){
parent=parent->sLeft;
}
}
So if the first if statement was executed then parent can be set to NULL. However in the second statement you are trying to access the data member iData for such a NULL pointer.
So there must be at least
while(parent!=NULL){
temp=parent;
if(iElement>parent->iData){
parent=parent->sRight;
}
else if(iElement<parent->iData){
parent=parent->sLeft;
}
}
The second problem with this loop is if the used will supply a duplicate value then this loop will be infinite because the pointer parent is not changed.
Also there will be a memory leak because the memory was already allocated for the pointer current though neither node shall be appended in case of a duplicate value.
So you need to process the case when the user supplied a duplicate value.
The function can be implemented the following way as it is shown in the demonstrative program.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int iData;
struct Node *sLeft;
struct Node *sRight;
};
struct Node *sRoot = NULL;
int insert( int iElement )
{
int success = 1;
struct Node **current = &sRoot;
while ( success && *current != NULL )
{
if ( iElement < ( *current )->iData )
{
current = &( *current )->sLeft;
}
else if ( ( *current )->iData < iElement )
{
current = &( *current )->sRight;
}
else
{
success = 0;
}
}
if ( success )
{
*current = malloc( sizeof( struct Node ) );
success = *current != NULL;
if ( success )
{
( *current )->iData = iElement;
( *current )->sLeft = NULL;
( *current )->sRight = NULL;
}
}
return success;
}
int main(void)
{
insert( 10 );
insert( 9 );
insert( 11 );
insert( 12 );
insert( 8 );
insert( 7 );
return 0;
}
Take into account that it is a bad idea when a function depends on global variables.
So it is better to declare it like with one more parameter
int insert( struct Node **sRoot, int iElement );
Here is the modified one, explaination I kept in comments.
void insert(int iElement){
if(sRoot==NULL){ //Initially sRoot is NULL
sRoot=(struct Node*)malloc(sizeof(struct Node));
sRoot->iData=iElement;
sRoot->sLeft=NULL;
sRoot->sRight=NULL;
}
else{
struct Node *current=(struct Node*)malloc(sizeof(struct Node));
current->iData=iElement;
current->sLeft=NULL;
current->sRight=NULL;
struct Node *parent;
struct Node *temp;
parent=sRoot;
while(parent!=NULL){ /* it fails when parent is NULL */
if(iElement > parent->iData){
if(parent->sRight ! = NULL)/* need to check if parent->right is null or not */
parent->sRight = current;/*if not NULL then put i
t here */
else
parent = parent->sRight;/* update the parent */
}
if(iElement < parent->iData){
if(parent->sLeft ! = NULL)
parent->sLeft = current;
else
parent=parent->sLeft;
}
}
}
}
Related
#include <stdlib.h>
#include <stdio.h>
#include "sorted_tree.h"
int insert_value(int value, struct TreeNode *n) {
if (value < n->value) {
if (n->left_child == NULL) {
struct TreeNode t = {0};
struct TreeNode *tpointer = &t;
tpointer->value = value;
tpointer->left_child = NULL;
tpointer->right_child = NULL;
n->left_child = tpointer;
printf("links eingefügt\n");
}
else {
insert_value(value, n->left_child);
}
return 0;
}
else if (value > n->value) {
if (n->right_child == NULL) {
struct TreeNode t = {0};
struct TreeNode *tpointer = &t;
tpointer->value = value;
tpointer->left_child = NULL;
tpointer->right_child = NULL;
n->right_child = tpointer;
printf("rechts eingefügt\n");
}
else {
insert_value(value, n->right_child);
}
return 0;
}
else {
return 1;
}
}
void print_inorder(struct TreeNode *n) {
if (n == NULL) {
printf("r");
return;
}
else {
print_inorder(n->left_child);
printf("%d ", n->value);
print_inorder(n->right_child);
}
}
int main() {
struct TreeNode t = {0};
struct TreeNode *tpointer = &t;
tpointer->value = 5;
tpointer->left_child = NULL;
tpointer->right_child = NULL;
insert_value(6, tpointer);
printf("%d", tpointer->right_child->value);
printf("%d", tpointer->right_child->value);
}
The first printf() in the main outputs "6" which is correct, but the second one outputs a hug random nummer as if the address has been changed. The 6 should be inserted into the right child node so I expected 66 as the output. Why those this happen and how can I fix it?
struct TreeNode t={0};
struct TreeNode *tpointer=&t;
tpointer->value=value;
Those blocks of code inside the if/else if of insert_value are not correct. This is because struct TreeNode t={0}; creates an automatic variable with lifetime only within the enclosing scope. In this case, the lifetime is only within the if/else if block. Keeping a reference to the variable and using it beyond that will result in Undefined Behaviour.
The solution is to create variables that have lifetimes beyond the function. The most common way to do that is to use dynamically allocated memory:
struct TreeNode *tpointer = malloc(sizeof(*tpointer));
Don't forget to free all dynamically allocated memory when it is no longer needed.
The approach when a first node of a tree is not allocated dynamically as in your program
struct TreeNode t={0};
struct TreeNode *tpointer=&t;
tpointer->value=5;
tpointer->left_child=NULL;
tpointer->right_child=NULL;
is not good. In fact you can not create or use an empty tree.
All nodes in a tree should be allocated dynamically when it is required.
So the pointer n within the function insert_value in general can be equal to NULL for an empty tree. You need to check it. Otherwise statements like this
if(value<n->value){
can invoke undefined behavior.
Also within the function you are setting a pointer to a local object of the type struct TreeNode as for example
struct TreeNode t={0};
struct TreeNode *tpointer=&t;
After exiting the function the local object t will not be alive. So an invalid pointer will be added to the tree.
You need to allocate a new node dynamically.
Also the function in fact returns an arbitrary number 0 or 1 because the function does not return the final value of subsequent recursive calls of the function.
Also it would be logically more consistent to return 1 in case when a new node is added and 0 otherwise.
I would declare and define the function the following way
int insert_value( struct TreeNode **n, int value )
{
if ( *n == NULL )
{
*n = malloc( sizeof( struct TreeNode ) );
( *n )->value = value;
( *n )->left_child = NULL;
( *n )->right_child = NULL;
return 1;
}
else if ( value < ( *n )->value )
{
return insert_value( &( *n )->left_child, value );
}
else if ( ( *n )->value < value )
{
return insert_value( &( *n )->right_child, value );
}
else
{
return 0;
}
}
And if in main you have a pointer to the root node declared like
struct TreeNode *root = NULL;
then the function is called like
insert_value( &root, value );
I have a problem with linked lists in C. I made a function that created a new node of the list with some information (char *description) and added it to its end. The code is following:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
char *description;
struct node *next;
};
// The function to create a node and append it to the linked list of nodes
struct node* create_node(struct node *first, char *description) {
struct node *current = first;
// Iteration through the list until the end
while(current != NULL) {
node++;
current = current -> next;
}
// Now pointer current points at the end of the list, first -> next. How to assign the pointer new to first -> next through current?
struct node *new = malloc(sizeof(struct container));
new -> next = NULL;
new -> description = malloc(sizeof(description));
memcpy(new -> description, description, sizeof(description));
current = new;
return current;
}
int main() {
// Creating the first node
struct node *first = create_node(NULL, "First");
// Creating and appending the second node to the list
create_node(first, "Second");
printf("%d\n", first -> next == NULL); // Prints 1, the newly created node hasn't been appended
return 0;
}
I searched how to create the list of the kind and saw very similar ways of how to do it. I know that it's something basic and most likely there's a simple solution, but I can't find it.
Thanks everyone for respond.
For starters the function name create_node is confusing. It is much better to name the function at least like append_node.
The second function parameter should have the qualifier const because the passed string is not changed in the function.
In these statements
new -> description = malloc(sizeof(description));
memcpy(new -> description, description, sizeof(description));
you are allocating memory of the size equal either to 8 or to 4 bytes depending on the value of sizeof( char * ) and correspondingly coping this number of bytes.
You have at least to write
new -> description = malloc( strlen(description));
memcpy(new -> description, description, strlen(description));
But it would be better if you were copying the whole string.
The function has a bug. It does not append a node to the list because within the function there is changed the local pointer current that is not chained to the list.
Take into account that memory allocation can fail. You should process such a situation.
The function can be safer and simpler if to pass the pointer to the head node by reference.
Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node
{
char *description;
struct node *next;
};
// The function to create a node and append it to the linked list of nodes
int append_node( struct node **head, const char *description )
{
struct node *new_node = malloc( sizeof( struct node ) );
int success = new_node != NULL;
if ( success )
{
new_node->description = malloc( strlen( description ) + 1 );
success = new_node->description != NULL;
if ( success )
{
strcpy( new_node->description, description );
new_node->next = NULL;
while ( *head != NULL )
{
head = &( *head )->next;
}
*head = new_node;
}
else
{
free( new_node );
}
}
return success;
}
int main( void )
{
// Creating the first node
struct node *head = NULL;
if ( append_node( &head, "first" ) )
{
printf( "%s\n", head->description );
}
return 0;
}
The program output is
first
Hi I am new at this community. Lets try to help.
I thik you are pointing to the last node of the list and changing it to the new one at line
current = new;
But to link the new node you should save it in the field next of the node, try:
current->next=new;
I hope help you, bye :).
I am trying to implement a Binary Serach Tree using C. Here in this code I added few values to the tree and then trying to check whether that values is in the tree. But my attempted code always return true.
I have checked many times. I am still learning C programming.
Here is my code.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct BSTnode {
int data;
struct BSTnode *left;
struct BSTnode *right;
} BSTnode;
BSTnode *getNewNode(int data){
BSTnode *newNode = (BSTnode*)malloc(sizeof(BSTnode));
newNode->data=data;
newNode->left=newNode->right=NULL;
}
BSTnode* InsertNew(BSTnode *root,int data){
if(root == NULL){
root = getNewNode(data);
}
else if(data <= root->data){
root->left = InsertNew(root->left,data);
} else{
root->right = InsertNew(root->right,data);
}
return root;
}
bool search(BSTnode *root, int data){
if(root== NULL) return false;
else if(root->data == data) return true;
else if (data <= root->data) return search(root->left,data);
else return search(root->right,data);
}
int main()
{
//node to store root
BSTnode *root = NULL;
root = InsertNew(root,34);
root = InsertNew(root,4);
root = InsertNew(root,3);
root = InsertNew(root,1);
int num;
printf("enter a number : \n");
num =scanf("%d");
if(search(root,num)==true){
printf("found");
}else{
printf("not found");
}
return 0;
}
What am I missing here?
Thanks in advance.
You are missing that
num =scanf("%d");
doesn't do what you think it does (scanf returns the number of items successfully converted or -1 on EOF). You didn't crank your compiler's warning level high enough to tell you that you need
if (scanf ("%d", &num) != 1) {
/* complain */
}
In your broken program, scanf() happens to return 1 (because it converted 1 item and wrote it to random memory) and since there's a 1 in the tree, you always get true.
In addition to the error pointed out by #Jens you are not returning a value from getNewNode. Add a statement:
return newNode;
at the end of that function. Here is a fixed example on ideone
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
The function getNewNode
BSTnode *getNewNode(int data){
BSTnode *newNode = (BSTnode*)malloc(sizeof(BSTnode));
newNode->data=data;
newNode->left=newNode->right=NULL;
}
has undefined behavior because it returns nothing though has the return type BSTnode *.
The function can be defined the following way
BSTnode * getNewNode( int data )
{
BSTnode *newNode = ( BSTnode * )malloc( sizeof( BSTnode ) );
if ( newNode != NULL )
{
newNode->data = data;
newNode->left = newNode->right = NULL;
}
return newNode;
}
The function InsertNew is wrong.Take into account that for binary search tree there is usually used the operator < instead of the operator <=.
These statements
root->left = InsertNew(root->left,data);
and
root->right = InsertNew(root->right,data);
do not make sense and overwrites the values of root->left and root->right of nodes that shall not be actually changed. Also the created node can be equal to NULL and in this case the original root node will be also overwritten by NULL.
It is better to pass the original root node by reference through pointer.
Also you should use operator < instead of the operator <=.
The function definition can look the following way
BSTnode * InsertNew( BSTnode **root,int data )
{
if ( *root == NULL )
{
*root = getNewNode( data );
return *root;
}
else if ( data < ( *root )->data )
{
return InsertNew( &( *root->left ), data );
}
else
{
return InsertNew( &( *root->right ), data );
}
}
and the function can be called like
InsertNew( &root, 34 );
without assigning the return pointer to the root node. The return value can be checked in an if statement if it is needed.
If you do not want to have duplicate values in the tree then the function can be written the following way
BSTnode * InsertNew( BSTnode **root,int data )
{
if ( *root == NULL )
{
*root = getNewNode( data );
return *root;
}
else if ( data < ( *root )->data )
{
return InsertNew( &( *root->left ), data );
}
else if ( ( *root )->data < data )
{
return InsertNew( &( *root->right ), data );
}
else
{
return NULL;
}
}
Correspondingly the function search should be defined like
bool search( BSTnode *root, int data )
{
if ( root == NULL )
{
return false;
}
else if ( data < root->data )
{
return search( root->left, data );
}
else if ( root->data < data )
{
return search( root->right, data );
}
else
{
return true;
}
}
The using of the function scanf in this statement
num =scanf("%d");
is wrong.
The correct call will look like
printf( "enter a number : " );
scanf( "%d", &num );
You can also check whether the call was successful by using the condition in an if statement
if ( scanf( "%d", &num ) == 1 )
{
//...
}
And you should free all allocated memory for the tree before exiting the program.
In general it is better to use the following condition
if(search(root,num) ){
instead of the strict comparison with true
if(search(root,num)==true){
because if the function will be rewritten such a way that in the case of success it will return any non-zero value then the strict comparison with true will not work.
I want to insert data to the tree using this function:
struct treeNode{
data* val;
struct treeNode *left, *right, *parent;
};
void insert(data *d, struct treeNode **leaf, struct treeNode **leaf_par)
{
if( *leaf == 0 )
{
*leaf = (struct treeNode*) malloc( sizeof( struct treeNode ) );
(*leaf)->val = d;
/* initialize the children to null */
(*leaf)->left = 0;
(*leaf)->right = 0;
/* initialize the parent */
(*leaf)->parent = *leaf_par; //here I receive segmentation fault
}
else if(strcmp(d->name, (*leaf)->val->name) < 0)
{
insert( d, &(*leaf)->left, &(*leaf) );
}
else if(strcmp(d->name, (*leaf)->val->name) > 0)
{
insert( d, &(*leaf)->right, &(*leaf) );
}
}
In main I have:
struct treeNode *root = NULL;
data d1 = {"Smith"};
insert(&d1, &root, NULL);
Segmentation fault is there:
(*leaf)->parent = *leaf_par;
At first time *leaf_par is NULL and I don't know why it's not running correctly. How should I fix my insert function? Without "parent" pointer it's easy, but I have to do that with "parent" and it's not working.
You are trying to dereference NULL; don't do that.
A simple fix for your first insert is:
insert(&d1, &root, &root);
Deeper inserts into the recursion will fix the pointer.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node *tree_ptr;
typedef struct table * Table;
struct node
{
char* element;
tree_ptr left, right;
};
typedef struct table
{
tree_ptr head;
int tree_h;
}table;
char* key = NULL;
Table insert(char* insert_key,Table t)
{
int height = 0;
//tree_ptr ptr = t->head;
tree_ptr *ptr = &(t->head);
key = strdup(insert_key);
tree_ptr new_node = malloc(sizeof(struct node));
new_node->element = key;
new_node->left = NULL;
new_node->right = NULL;
if ( t->head==NULL ){
*ptr = new_node;
t->tree_h = 0;
printf("head:%s\n",t->head->element);
return t;
}
while(1){
if ( strcmp(insert_key, (*ptr)->element)<0 ){
if ( (*ptr)->left ==NULL ){
(*ptr)->left = new_node;
height++;
if ( height > t->tree_h)
t->tree_h = height;
break;
}
else{
(*ptr) = (*ptr)->left;
height++;
}
}
else if ( strcmp(insert_key, (*ptr)->element)>0 ){
if ( (*ptr)->right ==NULL ){
(*ptr)->right = new_node;
height++;
if ( height > t->tree_h)
t->tree_h = height;
break;
}
else{
(*ptr) = (*ptr)->right;
height++;
}
}
else break;
}
return t;
}
int main() {
Table t = malloc(sizeof(table));
t->head = NULL;
t = insert("one", t);
t = insert("two", t);
t = insert("three", t);
printf("%s\n",t->head->element);
return 0;
}
The above is a simplified program, some definition code is given, so I could not change the basic structure, like table, Table, node, tree_ptr, while others could be changed.
What I am trying to implement is a spellchecking, the table stored the head of the tree and some other properties of the tree(which is omitted here), the tree is implemented as an ordered binary tree.
I find that, insert() works well up to two times, after the (*ptr) = (*ptr)->right; the t->head is changed as well. So after using it two times, I lost the head of the tree.
How to modify my insert()?
To insert a node into a tree you first have to search for an empty leaf. Apart from this you do not modify t, so there is no need of writing it back by return value:
void insert( char* insert_key, Table t )
{
// serach empty leaf, where to insert the new node
tree_ptr *ptr = &(t->head); // start at head
while ( *ptr != NULL ) // end if empty leaf is found
{
int cmpRes = strcmp( insert_key, (*ptr)->element );
if ( cmpRes == 0 )
return; // insert_key already is member of tree
if ( cmpRes < 0 )
ptr = &((*ptr)->left); // step down to left child
else
ptr = &((*ptr)->right); // step down to right child
}
// create new node
tree_ptr new_node = malloc( sizeof(struct node) );
new_node->element = strdup( insert_key );
new_node->left = NULL;
new_node->right = NULL;
// place new node at empty leaf
*ptr = new_node;
}
With this recursive function you can print your tree:
void printTree( tree_ptr ptr )
{
if ( ptr == NULL )
return;
printTree( ptr->left );
printf( "%s\n", ptr->element );
printTree( ptr->right );
}
printTree( t->head );
And with this one you can free all nodes of your tree:
void deleteTree( tree_ptr ptr )
{
if ( ptr == NULL )
return;
deleteTree( ptr->left );
deleteTree( ptr->right );
free( ptr );
}
deleteTree( t->head );
t->head = NULL;
The problem is ptr is pointing to the address of the pointer to a struct node, instead of directly pointing to a struct node:
tree_ptr *ptr = &(t->head);
Then when iterating in the while loop, you aren't changing the pointer ptr, but the pointer it is pointing to, which is t->head:
(*ptr) = (*ptr)->left;
This overwrites the pointer, t->head on every iteration, effectively erasing the nodes that pointer pointed to, and leaking memory.
Instead use a normal pointer to the struct node:
struct node* iter = t->head;
...
if ( strcmp(insert_key, iter->element)<0 ){
...
}
else{
iter = iter->left;
....
And I would highly suggest removing those typedefs that hide the pointer, because they make the code hard to read and obfuscate the types, which is not desirable in this context:
typedef struct node *tree_ptr;
typedef struct table * Table;
Also note that if the loop finds a duplicate, the allocated node is not freed, leaking the memory.