Binary Search Tree does not recognize values properly - c

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.

Related

Getting user input for the deletion of the desired linked list element

NodePointer deleteNode(NodePointer head,int number)
{
NodePointer ptrNode;
NodePointer ptrNodePrev;
int count;
if(head == NULL)
{
printf("There is no element at list");
}
if(number == 1)
{
ptrNodePrev=head;
head=head->next;
free(ptrNodePrev);
}
else{
ptrNode=head;
while(ptrNode->next != NULL && count+1 != number){
count++;
ptrNodePrev=ptrNode;
ptrNode=ptrNode->next;
}
ptrNode=ptrNode->next;
printf("Node: %d-%d-%d - %s",ptrNodePrev->next->x.year,
ptrNodePrev->next->x.month,
ptrNodePrev->next->x.day,
ptrNodePrev->next->x.event);
printf("Successfully deleted");
free(ptrNodePrev->next);
ptrNodePrev->next=ptrNode;
}
return head;
}
Hi I've been learning single linked lists and wanted to do a example about it.Basically i ask user to input how many nodes does he want and then he fills them. After that i ask them to delete a node then they will enter a number which will supposedly deletes the according node.Its fine if the number inputed is not 1 but if it is then i would basically get random numbers. I dont get why it happens i looked through most of the questions about this topic here but couldnt find reason.Can anyone explain my mistake please ?
Actually when number is equal to 1 then the function works correctly.
NodePointer deleteNode(NodePointer head,int number)
{
NodePointer ptrNode;
NodePointer ptrNodePrev;
int count;
if(head == NULL)
{
printf("There is no element at list");
}
if(number == 1)
{
ptrNodePrev=head;
head=head->next;
free(ptrNodePrev);
}
else
{
//...
}
return head;
}
Maybe in main you forgot to assign the return value of the function to the pointer to the head node like
head = deleteNode( head, 1 );
Otherwise the function has undefined behavior because 1) the variable count is not initialized and 2) you do not check that after the while loop count + 1 is equal to number
while(ptrNode->next != NULL && count+1 != number){
count++;
ptrNodePrev=ptrNode;
ptrNode=ptrNode->next;
}
ptrNode=ptrNode->next;
//...
Pay attention to that in C indices start from 0. And the second parameter of the function should have an unsigned integer type as for example size_t. Otherwise the user is allowed to pass to the function a negative value.
Also the function should not issue any message.
The function can be declared and defined the following way.
int deleteNode( NodePointer *head, size_t n )
{
while ( n-- && *head != NULL ) head = &( *head )->next;
int success = *head != NULL;
if ( success )
{
NodePointer current = *head;
*head = ( *head )->next;
free( current );
}
return success;
}
And if in main you have a declaration of the pointer like
NodePointer head = NULL;
//...
then the function is called like
deleteNode( &head, n );
where n is some value specifying an index in the list starting form 0. That is if you want to delete the first node then you should write
deleteNode( &head, 0 );

Why does the value of a Pointer change after a print?

#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 );

insert an element in binary search tree gives stopped working

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;
}
}
}
}

a nested struct with pointers

#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.

Binary Search Tree Insert Function In C

For future viewers of this question who might need help in this type of problem: I fixed it by combining the 2 functions (InsertNode() and InTree()) I'm not sure if this is bad practice and I'll get back to you guys with if it actually really does solve the problem or if it just masks it, but it seems to be working...
I've looked through various answers on this website (as well as others) and from those I've gotten solutions which didn't help (tried and didn't work or just didn't differ from my program).
The insert function (I've isolated it and think this is the problematic code) has some bug somewhere that causes my program to crash.
NP InTree(NP Node,NP Root)
{
if (Root == NULL)
{
Root=Node;
return Root;
}
else
{
if (Node->Input < Root->Input)
{
return InTree(Node,Root->Left);
}
else if (Node->Input > Root->Input)
{
return InTree(Node,Root->Right);
}
else
{
puts("Duplicate");
return NULL;
}
}
}
void InsertNode(int I, TP Tree)
{
NP Node;
Node=(NP)malloc(sizeof(struct AVLNode));
InitializeNode(Node);
Node->Input=I;
Node->Height=0;
Node->Left=NULL;
Node->Right=NULL;
InTree(Node,Tree->Root);
Tree->Size++;
}
NP is a Node Pointer, TP is a Tree Pointer
The Node variable is the initialized node sent through InsertNode()
void InitializeTree(TP Tree)
{
Tree->Root=NULL;
Tree->Size=0;
}
void InitializeNode(NP Node)
{
Node->Input=0;
Node->Height=0;
}
The above are my Initialize functions just in case you need to see them.
The memory for the Tree is allocated in the main class before any of the functions are called.
The main problem from what I saw through testing is that once Root is made equal to Node it remains null.
Any ideas how I can get past the problem?
In the InTree function, where the Root is made equal to Node, it only changes the memory locally.
Instead, you may need to use a pointer to a pointer to achieve what you're trying.
void InsertNode(int I, TP Tree) allocates mem for a new node, but when you call NP InTree(NP Node,NP Root) you only modify the local pointer address. You need to either use a pointer to a pointer (i.e. NP InTree(NP Node, NP *ppRoot)) or the following example:
if (Node->Input < Root->Input) {
if(Root->Left == NULL) {
Root->Left = Node;
} else {
return InTree(Node,Root->Left);
}
} else if (Node->Input > Root->Input) {
if(Root->Right== NULL) {
Root->Right= Node;
} else {
return InTree(Node,Root->Right);
}
} else {
puts("Duplicate");
return NULL;
}
Ps. I notice you allocate struct AVLNode...is NP a typedef of AVLNode (typedef struct AVLNode* NP)? I don't know what your structures are so I can't say. Technically AVLs are different from B-trees in that they are self balancing... http://en.wikipedia.org/wiki/AVL_tree
I'd do it something like this. Your insert function doesn't differentiate between the special case (an empty tree) and the general case (a non-empty tree).
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct NODE
{
struct NODE *left ;
struct NODE *right ;
int value ;
int depth ;
} NODE ;
typedef struct TREE
{
NODE *root ;
int count ;
} TREE ;
NODE *node_create( int value )
{
NODE *instance = (NODE*) calloc( 1 , sizeof(NODE) ) ;
instance->value = value ;
return instance ;
}
TREE *tree_create()
{
TREE *instance = (TREE*) calloc( 1 , sizeof(TREE) ) ;
return instance ;
}
NODE *tree_find_and_insert( NODE *parent , int value )
{
NODE *child = NULL ;
if ( value < parent->value )
{
if ( parent->left == NULL )
{
child = node_create(value) ;
child->depth = ++ parent->depth ;
parent->left = child ;
return child ;
}
else
{
return tree_find_and_insert(parent->left , value ) ;
}
}
else if ( value > parent->value )
{
if ( parent->right == NULL )
{
child = node_create(value) ;
child->depth = ++ parent->depth ;
parent->right = child ;
return child ;
}
else
{
return tree_find_and_insert( parent->right , value ) ;
}
}
else /* ( value == parent->value ) */
{
// NO-OP by design: dupes fall out and NULL is returned
}
return child ;
}
NODE *tree_insert( TREE *tree , int value )
{
NODE *inserted = NULL ;
if ( tree->root == NULL )
{
tree->root = node_create( value ) ;
tree->count = 1 ;
inserted = tree->root ;
}
else
{
inserted = tree_find_and_insert( tree->root , value ) ;
}
return inserted ;
}
int main ( int argc , char *argv[] )
{
TREE *my_tree = tree_create() ;
int i ;
for ( i = 1 ; i < argc ; ++i )
{
char *arg = argv[i] ;
int n = atoi(arg) ;
tree_insert( my_tree , n ) ;
}
return 0 ;
}

Resources