Binary Search Tree Insert Function In C - 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 ;
}

Related

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

see get min value of nodes, exceptional case

Given the following struct:
typedef struct node_t {
int x;
struct node_t *next;
} *Node;
Please Note: the definition above is given to me as is and can't be changed.
I wrote the following function:
inline int getMin(Node *list1,Node *list2)
{
int first_value=INT_MAX,second_value=INT_MAX;
if (*list1)
{
first_value=(*list1)->x;
}
if (*list2)
{
second_value=(*list2)->x;
}
if (first_value<second_value)
{
*list1=(*list1)->next;
return first_value;
}
*list2=(*list2)->next;
return second_value;
}
It receives 2 pointers to a series of Nodes while each node has two attributes: x and next (a pointer to the next code)
My code should get the minimum value when comparing the values of the current two nodes, while it works fine with 99% of the cases it doesn't work with the case where list1 points to a node that its value is INT_MAX and next points to null and list2 is NULL
how can I fix this?
I fixed this by changing the following code:
if (first_value<second_value) to
if (first_value<=second_value)
but I have a new problem:
list2 points to a node that its value is INT_MAX and next points to null and list1 is NULL
Edit: Here is the last version of my code:
helper functions:
int advance(Node *node) {
int node_value = (*node)->x;
*node = (*node)->next;
return node_value;
}
int getMin(Node *list1, Node *list2) {
assert(*list1 || *list2);
if (!(*list1)) {
return advance(list2);
}
if (!(*list2)) {
return advance(list1);
}
if ((*list1)->x < (*list2)->x) {
return advance(list1);
}
return advance(list2);
}
main function:
ErrorCode mergeSortedLists(Node list1, Node list2, Node *merged_out) {
if (!merged_out) {
return NULL_ARGUMENT;
}
if (!list1 || !list2) {
return EMPTY_LIST;
}
if (!isListSorted(list1) || !isListSorted(list2)) {
return UNSORTED_LIST;
}
Node ptr = *merged_out;
int total_len = getListLength(list1) + getListLength(list2);
for (int i = 0; i < total_len; i++) {
int min = getMin(&list1, &list2);
if (i != 0) {
ptr->next = malloc(sizeof(*ptr));
if (!ptr->next) {
destroyList(*merged_out);
return MEMORY_ERROR;
}
ptr = ptr->next;
}
ptr->x = min;
}
ptr->next = NULL;
return SUCCESS;
}
This is the classical merge sort code where you have four cases provided that not both lists are exhausted:
a is exhausted;
b is exhausted;
a < b and
a ≥ b.
You have tried to coalesce the two first cases where one of the nodes is null with the comparison, but because your lists can have INT_MAX as value, that solution isn't robust.
Write out these cases explicitly. First a little auxiliary function that advances a node and returns the value:
static int advance(Node *nd)
{
int res = (*nd)->x;
*nd = (*nd)->next;
return res;
}
Now your actual function is very simple:
int getMin(Node *list1, Node *list2)
{
assert(*list1 || *list2);
if (*list1 == NULL) return advance(list2);
if (*list2 == NULL) return advance(list1);
if ((*list1)->x < (*list2)->x) return advance(list1);
return advance(list2);
}
See it in action on ideone.

Linked List Delete Node , Simple linked list

I'm trying to implement a function that deletes nodes from a linked list. So far, I can delete just the first node of the list(3).
I tried to go to the for loop from delete, I thought that the memory is not well allocated, I have been struggling for a few days and I don't understand, please help me a little, it's the topic I received from college.
#include <stdio.h>
#include <stdlib.h>
typedef struct nod
{
int key;
struct nod *urm;
} NOD;
NOD *first=0,*last=0;
void add(int x)
{
NOD *p=(NOD*)malloc(sizeof(NOD));
p->key=x;
p->urm=0;
if(0==first)
{
first=p;
last=p;
}
else{
last->urm=p;
last=p;
}
}
void delete(int x)
{
NOD *q,*p;
if(first->key==x)
{
p=first;
first=first->urm;
free(p);
}
else{
for(p=q=first;p=0;q=p,p=p->urm)
{
if(p->key==x)
{
q->urm=p->urm;
if(p==last)
{
last=q;
}
free(p);
}
}
}
}
void show()
{
for(NOD *p=first;p!=0;p=p->urm)
{
printf("%d ",p->key);
}
printf("\n");
}
int main()
{
add(3);
add(1);
add(2);
add(5);
show();
delete(2);
show();
return 0;
}
For starters the code you showed is not a C++ code. It is a C code.
It is a bad idea to define global variables like first and last and when functions depend on global variables. In this case you can not create more than one list in a program.
As for the function delete then in general it has undefined behavior. It can be called for an empty list.
Moreover in this ;loop
for(p=q=first;p=0;q=p,p=p->urm)
there is a typo in the condition expression. You are using the assignment operator instead of the comparison operator.
And you function ignore the case when the list contains only one node because in this case it does not update the last node.
Nevertheless using your approach the function delete can look the following way.
void delete(int x)
{
if ( first )
{
if ( first->key == x )
{
NOD *tmp = first;
first = first->urm;
free( tmp );
if ( first == NULL ) last = NULL;
}
else
{
NOD *p = first;
while ( p->urm != NULL && p->urm->key != x )
{
p = p->urm;
}
if ( p->urm != NULL )
{
NOD *tmp = p->urm;
p->urm = p->urm->urm;
free( tmp );
if ( p->urm == NULL ) last = p;
}
}
}
}
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
typedef struct nod
{
int key;
struct nod *urm;
} NOD;
NOD *first=0,*last=0;
void add(int x)
{
NOD *p=(NOD*)malloc(sizeof(NOD));
p->key=x;
p->urm=0;
if(0==first)
{
first=p;
last=p;
}
else{
last->urm=p;
last=p;
}
}
void delete(int x)
{
if ( first )
{
if ( first->key == x )
{
NOD *tmp = first;
first = first->urm;
free( tmp );
if ( first == NULL ) last = NULL;
}
else
{
NOD *p = first;
while ( p->urm != NULL && p->urm->key != x )
{
p = p->urm;
}
if ( p->urm != NULL )
{
NOD *tmp = p->urm;
p->urm = p->urm->urm;
free( tmp );
if ( p->urm == NULL ) last = p;
}
}
}
}
void show()
{
for(NOD *p=first;p!=0;p=p->urm)
{
printf("%d ",p->key);
}
printf("\n");
}
int main()
{
add(10);
add(20);
add(30);
add(40);
show();
delete(30);
show();
add( 50 );
add( 60 );
add( 70 );
add( 80 );
show();
delete(80);
show();
return 0;
}
Its output is
10 20 30 40
10 20 40
10 20 40 50 60 70 80
10 20 40 50 60 70
You can greatly simplify deleting a node from your list by using both a pointer-to-pointer to NOD and a pointer-to NOD to iterate over the list. This allows you to set the node at the current address to the node->urm eliminating the need to keep track of the previous node in the list, e.g.
/** delete node with key v from list (for loop) */
void delete (int v)
{
NOD **ppn = &first; /* pointer to pointer to first*/
NOD *pn = first; /* pointer to first */
for (; pn; ppn = &pn->urm, pn = pn->urm) {
if (pn->key == v) {
*ppn = pn->urm; /* set node at address to next node */
free (pn); /* free deleted node */
break;
}
}
}
See Linus on Understanding Pointers for further discussion on the advantages of using the address of a node in addition to a pointer to node.
I think your for loop condition is incorrect inside delete functions:
for(q=first, p=first->urm; p!=0; q=p, p=p->urm)
just change the condition, then it should work.

Binary Search Tree does not recognize values properly

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.

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.

Resources