Why does this tree display function print only the first element? - c

The display function I've used for printing the tree only seems to print the first element and not the rest. I don't know why I suspect the insert function which I've used without recursion might be the cause but can't seem to understand where it goes wrong. Any explanation on how to correct it or where the code fails would be helpful. Thanks.
#include <stdio.h>
#include<stdlib.h>
void insert(int data_add,struct tree *temp);
void display(struct tree *temp);
struct tree
{
int data;
struct tree *left;
struct tree *right;
} *root = NULL;
int main()
{
int data_add,n;
while(1)
{
printf("\n\n1.Add\n2.Display\n4.Exit\n");
scanf("%d",&n);
switch(n)
{
case 1: printf("\nEnter the element to add ");
scanf("%d",&data_add);
insert(data_add,root);
break;
case 2: printf("The nos are: ");
display(root);
break;
/*case 3: printf("The nos are: ");
reversedisplay(root);*/
case 4: exit(1);
break;
default: printf("\nChoose a appropriate option");
}
}
}
void insert(int data,struct tree *temp)
{
struct tree *current;
current = (struct tree*) malloc(sizeof(struct tree));
current->data = data;
if(root == NULL)
{
root = current;
current->left = NULL;
current->right = NULL;
}
else
{
while(temp!=NULL)
{
if(data<temp->data)
{
temp = temp->left;
}
else
{
temp = temp->right;
}
}
temp = current;
current->left = NULL;
current->right = NULL;
}
}
void display(struct tree *temp)
{
if(temp == NULL)
return;
display(temp->right);
display(temp->left);
printf("%d",temp->data);
}

The problem in your code is that while inserting a node you are not making the new inserted node as the left or right child of any node, because of which the new node is not actually inserted in your tree.
Your code where things go wrong -
temp = current;
current->left = NULL;
current->right = NULL;
After coming out of the loop, temp is NULL , now current is assigned to temp, but there is no way to reach the new node from any other node in the tree, because it is not left/right child of any node in the tree.
Here I present the correct code for the insert function -
void insert(int data,struct tree *temp)
{
struct tree *current;
current = (struct tree*) malloc(sizeof(struct tree));
current->data = data;
current->left = NULL;
current->right = NULL;
if(root == NULL)
{
root = current;
current->left = NULL;
current->right = NULL;
}
else
{
struct tree *par=temp; //par is used to keep track of node whose left
//or right child will be the new node.
while(temp!=NULL)
{
par=temp;
if(data<temp->data)
temp=temp->left;
else temp=temp->right;
}
// The below part is used to make the new node as left or right child
// of the appropriate node.
if(data<par->data)
par->left=current;
else
par->right=current;
}
}
Moreover , slight change in your display function, change your printf statement to -
printf("%d ",temp->data); .
In previous version all the node values would be printed without no spaces giving an impression that only one number is printed.

The problem is in the insert function. You never link the new node to the old one. You would need to use pointers keep the address of the right or left node. Instead of that, you only copy the address of current node in the local temp variable. You code should be:
...
else
{
t = &temp;
while(*t!=NULL)
{
if(data<(*t)->data)
{
t = &(*t)->left;
}
else
{
t = &(*t)->right;
}
}
*t = current; // actually copy current in right of left of last node
current->left = NULL;
current->right = NULL;
}
But that's not all, in order to display the elements in order, you should change display to:
void display(struct tree *temp)
{
if(temp == NULL)
return;
display(temp->left); // left side first
printf("%d",temp->data); // then current
display(temp->right); // finally right side
}

Related

Why try to print the value in the left node and right node of the binary search tree causing a Segmentation fault?

I am trying to implement the insert operation of a binary search tree using C. Why does the following code show a Segmentation fault when trying to print the value of the left and right nodes of the root?
Please explain what caused this error exactly.
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node* left;
struct node* right;
};
struct node *root, *temp = NULL;
void insert(int data) {
struct node *newNode = (struct node*) malloc(sizeof(struct node));
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
if (root == NULL){
// if tree is empty insert the node as root
root = newNode;
}else {
// if the tree is not empty
temp = root;
while(temp != NULL) {
if(data <= root->data) {
temp = temp->left;
}
if(data > root->data) {
temp = temp->right;
}
}
temp = newNode;
}
}
int main() {
insert(7);
insert(4);
insert(8);
printf("\n\n------%d------", root->left->data);
printf("\n\n------%d------", root->right->data);
return 0;
}
The assignment temp = newNode only stores a pointer in the temp variable, not somewhere in the tree. So your tree's root node will never get any child. By consequence the main program is dereferencing a root->left pointer that is NULL, and this explains the error you get.
In order to really attach the new node at the right place in the tree, you need to modify a left or right member of some node. You can do this in several ways. One is to make temp a pointer-pointer, so that it will have the address of a left or right member. Then the assignment to *temp, will be an assignment to a node's left or right member, effectively extending the tree with that new node.
Here is the updated part of the code:
struct node **temp = &root;
while(*temp != NULL) {
if(data <= root->data) {
temp = &(*temp)->left;
}
if(data > root->data) {
temp = &(*temp)->right;
}
}
*temp = newNode;
okay you have a few issues here,
first of all, temp will point back to newNode, as you have not copied newNode's values to where temp is pointing now.
second and no less important, newNode is created within the scope of insert() - therefore, root will always remain null, as root points after execution of insert() to data wich no longer exists.
I have improved your code, and this definitely works as expected
hope it has helped.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node* left;
struct node* right;
}node;
node *root=NULL;
void insert(int data) {
node *temp = NULL;
if (root == NULL){
/* if tree is empty insert the node as root*/
root = malloc(sizeof(struct node));
root->data=data;
}else {
/*if the tree is not empty*/
temp = root;
while(temp->left!= NULL||temp->right!=NULL) {
if(data <= temp->data){
if(temp->left==NULL)
break;
else
temp = temp->left;
}
else if(data > temp->data){
if(temp->right==NULL)
break;
else
temp = temp->right;
}
}
if(data<= temp->data){
temp->left=malloc(sizeof(struct node));
(temp->left)->data=data;
}
else {
temp->right=malloc(sizeof(struct node));
(temp->right)->data=data;
}
/*temp=newNode;*/
}
}
int main() {
insert(7);
insert(4);
insert(8);
printf("\n\n------%d------", root->left->data);
printf("\n\n------%d------", root->right->data);
return 0;
}

How to implement the function delete of a binary search tree without recursion in C?

I try to implement the delete method but that doesn't work with me. I want to delete all nodes in the tree. The function has tree type of "struct tree" as a parameter so I can't use recursion; I want to do it with a loop.
That's my structure
typedef struct Node Node;
struct Node{
const void* data;
const void* value;
Node* left;
Node* right;
};
typedef struct Tree Tree;
struct Tree{
Node* root;
size_t size;
int (*comp)(const void *, const void *);
};
function delete
void freeTree(Tree* tree, bool TreeContent){
if(tree->root != NULL){
// free(tree->root->left);
// free(tree->root->right);
// free(tree->root);
}
}
function insert
bool insertInTree(Tree* bst, const void* key, const void* value){
if(bst->root == NULL){
Node* newNode = (Node*) malloc(sizeof(Node));
if(newNode == NULL){
printf("erreur d'allocation dynamique \n");
exit(1);
}
newNode->left = newNode->right = NULL;
newNode->value = value;
newNode->data = key;
return true;
}
else{
int isLeft = 0 ;
Node* Current = bst->root ;
Node* precedant = NULL;
while(Current != NULL){
int compare = bst->comp(&Current->data , &key);
precedant = Current;
if(compare == 1){
isLeft = 1;
Current = Current->left;
}
else if(compare == 0){
isLeft = 0;
Current = Current->right;
}
}
if(isLeft == 1){
Node* newNode = (Node*) malloc(sizeof(Node));
if(newNode == NULL){
printf("erreur d'allocation dynamique \n");
exit(1);
}
newNode->left = newNode->right = NULL;
newNode->value = value;
newNode->data = key;
precedant->left = newNode;
bst->size++;
return true;
}
else{
Node* newNode = (Node*) malloc(sizeof(Node));
if(newNode == NULL){
printf("erreur d'allocation dynamique \n");
exit(1);
}
newNode->left = newNode->right = NULL;
newNode->value = value;
newNode->data = key;
precedant->right = newNode;
bst->size++;
return true;
}
}
return false;
}
edit You don't want to use recursion because the freeTree function doesn't take a Node argument. In this case, you can remove that restriction by creating another function that is recursive, called initially by freeTree.
void freeTree(Tree* tree, bool TreeContent){
if(tree->root != NULL){
freeNode(tree->root);
tree->root = NULL;
}
}
The new freeNode could look like
void freeNode(Node *node) {
if (node->left) freeNode(node->left);
if (node->right) freeNode(node->right);
free(node);
}
Note that freeNode intent is to free the whole tree (otherwise the parent element's left or right [or root] would have to be set to NULL).
Your requirement is that you don't want to use recursion.
Any kind of traversal is not possible in O(n) time without use of a stack/queue (implicitly or explicitly). So we will use a stack (made using an array) and use it to delete all the nodes.
I understand that you have the size of the BST known, so you can create an array of appropriate size as -
struct Node* stack[bst->size];
int top = -1;
This stack will hold all the elements to be processed.
We will first add the root to the stack -
if(bst->root)
stack[++top] = bst->root;
Now we need to process all the nodes in the tree using a loop -
while(top>=0){
//Pop one node -
struct Node* node = stack[top--];
//Add its children to the stack;
if(node->left)
stack[++top] = node->left;
if(node->right)
stack[++top] = node->right;
// Now free the node as
free(node);
}
That is all, one by one each node will be added to the stack and the stack will become empty when all the nodes are done.
Also as a side note, in your insert function you need to do bst->size++ in the if(bst->root == NULL) branch. Else your size will be one less than actual number of nodes.

malloc in pointer received as argument

I'm implementing an binary search tree but for some reasons I 'm not able to add a node
my: input was :
a.value = 5;
add_bst_node(&t,a);
mystructures:
typedef struct BST_node{
entity value;
struct BST_node* left;
struct BST_node* right;
}BST_node;
typedef struct BST_tree{
BST_node* root;
}BST_tree;
my code for add a node:
void add_bst_node2(BST_node* root,entity* e){
if(!root){
root = (BST_node*)malloc(sizeof(BST_node));
root->value = *e;
root->left = NULL;
root->right = NULL;
return;
}
else if(great_than(&root->value,e))
add_bst_node2(root->left,e);
else
add_bst_node2(root->right,e);
}
void add_bst_node(BST_tree* t,entity e){
add_bst_node2(t->root,&e);
printf("%d\n",t->root==NULL);
}
Someone can explayn why I'can't add a node?
Apart from not passing double pointer to BST_node (i.e. BST_node**) in add_bst_node2() as noted in the comments, you also didn't implement the function properly.
Your implementation never really adds a node, but instead in enters into infinite recursion.
Here you can find some clean theory about BST - http://www.zentut.com/c-tutorial/c-binary-search-tree/
Here is an untested correction of your code. Note that here we pass pointer to BST_tree instead of BST_node
void add_bst_node2(BST_tree* tree,entity* e){
if(!tree->root){
/* If the binary search tree is empty, we just create a root node */
tree->root = bst_create_node(e);
return;
}
int is_left = 0;
BST_node* current_node = tree->root;
BST_node* prev = NULL;
/* Traverse the tree until we find the proper position for the new node.
* The position is denoted by 'current_node'
*/
while(current_node != NULL) {
prev = current_node;
if(greater_than(&current_node->value, e)) {
is_left = 1;
current_node = current_node->left;
} else {
is_left = 0;
current_node = current_node->right;
}
}
/* We finally know the position where we should add the new node */
if(is_left)
prev->left = bst_create_node(e);
else
prev->right = bst_create_node(e);
}
We introduce another function for creating and initializing a node...
BST_node *bst_create_node(entity *e)
{
BST_node *n = malloc(sizeof(BST_node));
n->value = *e;
n->left = NULL;
n->right = NULL;
return n;
}
And finally we change add_bst_node()
void add_bst_node(BST_tree* t,entity e){
add_bst_node2(t, &e);
printf("%d\n", t->root==NULL);
}
From what it seems, a is a struct BST_node and value is a variable in it. You have to either pass the value to the function and handle the node creation there, or pass the whole constructed node and just point to it from the existing tree.
first thing is that you put an unnecessary structure BST_tree.You do it in simple way like
struct node
{
int value;
node* left;
node* right;
};
struct node* root;
I suggest you try with this code
struct node* insert(struct node* r, int data)
{
if(r==NULL) // BST is not created created
{
r = (struct node*) malloc(sizeof(struct node)); // create a new node
r->value = data; // insert data to new node
// make left and right childs empty
r->left = NULL;
r->right = NULL;
}
// if the data is less than node value then we must put this in left sub-tree
else if(data < r->value){
r->left = insert(r->left, data);
}
// else this will be in the right subtree
else {
r->right = insert(r->right, data);
}
return r;
}`
`

Working tree traversal program seems like it does not work

I was new to trees in C. To learn more, I googled and found some nice example program. http://see-programming.blogspot.in/2013/03/insertion-deletion-and-traversal-in.html I copied it and ran it It worked perfectly. One of its functions was known as traverse. Its code is as follows:
void traverse(struct treeNode *node) {
if (node != NULL) {
traverse(node->left);
printf("%3d", node->data);
traverse(node->right);
}
return;
}
The whole program:
#include <stdio.h>
#include <stdlib.h>
struct treeNode {
int data;
struct treeNode *left, *right;
};
struct treeNode *root = NULL;
/* create a new node with the given data */
struct treeNode* createNode(int data) {
struct treeNode *newNode;
newNode = (struct treeNode *) malloc(sizeof (struct treeNode));
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return(newNode);
}
/* insertion in binary search tree */
void insertion(struct treeNode **node, int data) {
if (*node == NULL) {
*node = createNode(data);
} else if (data < (*node)->data) {
insertion(&(*node)->left, data);
} else if (data > (*node)->data) {
insertion(&(*node)->right, data);
}
}
/* deletion in binary search tree */
void deletion(struct treeNode **node, struct treeNode **parent, int data) {
struct treeNode *tmpNode, *tmpParent;
if (*node == NULL)
return;
if ((*node)->data == data) {
/* deleting the leaf node */
if (!(*node)->left && !(*node)->right) {
if (parent) {
/* delete leaf node */
if ((*parent)->left == *node)
(*parent)->left = NULL;
else
(*parent)->right = NULL;
free(*node);
} else {
/* delete root node with no children */
free(*node);
}
/* deleting node with one child */
} else if (!(*node)->right && (*node)->left) {
/* deleting node with left child alone */
tmpNode = *node;
(*parent)->right = (*node)->left;
free(tmpNode);
*node = (*parent)->right;
} else if ((*node)->right && !(*node)->left) {
/* deleting node with right child alone */
tmpNode = *node;
(*parent)->left = (*node)->right;
free(tmpNode);
(*node) = (*parent)->left;
} else if (!(*node)->right->left) {
/*
* deleting a node whose right child
* is the smallest node in the right
* subtree for the node to be deleted.
*/
tmpNode = *node;
(*node)->right->left = (*node)->left;
(*parent)->left = (*node)->right;
free(tmpNode);
*node = (*parent)->left;
} else {
/*
* Deleting a node with two children.
* First, find the smallest node in
* the right subtree. Replace the
* smallest node with the node to be
* deleted. Then, do proper connections
* for the children of replaced node.
*/
tmpNode = (*node)->right;
while (tmpNode->left) {
tmpParent = tmpNode;
tmpNode = tmpNode->left;
}
tmpParent->left = tmpNode->right;
tmpNode->left = (*node)->left;
tmpNode->right =(*node)->right;
free(*node);
*node = tmpNode;
}
} else if (data < (*node)->data) {
/* traverse towards left subtree */
deletion(&(*node)->left, node, data);
} else if (data > (*node)->data) {
/* traversing towards right subtree */
deletion(&(*node)->right, node, data);
}
}
/* search the given element in binary search tree */
void findElement(struct treeNode *node, int data) {
if (!node)
return;
else if (data < node->data) {
findElement(node->left, data);
} else if (data > node->data) {
findElement(node->right, data);
} else
printf("data found: %d\n", node->data);
return;
}
void traverse(struct treeNode *node) {
if (node != NULL) {
traverse(node->left);
printf("%3d", node->data);
traverse(node->right);
}
return;
}
int main() {
int data, ch;
while (1) {
printf("1. Insertion in Binary Search Tree\n");
printf("2. Deletion in Binary Search Tree\n");
printf("3. Search Element in Binary Search Tree\n");
printf("4. Inorder traversal\n5. Exit\n");
printf("Enter your choice:");
scanf("%d", &ch);
switch (ch) {
case 1:
while (1) {
printf("Enter your data:");
scanf("%d", &data);
insertion(&root, data);
printf("Continue Insertion(0/1):");
scanf("%d", &ch);
if (!ch)
break;
}
break;
case 2:
printf("Enter your data:");
scanf("%d", &data);
deletion(&root, NULL, data);
break;
case 3:
printf("Enter value for data:");
scanf("%d", &data);
findElement(root, data);
break;
case 4:
printf("Inorder Traversal:\n");
traverse(root);
printf("\n");
break;
case 5:
exit(0);
default:
printf("u've entered wrong option\n");
break;
}
}
return 0;
}
When I ran the program it worked perfectly. But when I analyzed the traverse function, I could not understand it. When you call the traverse function from the main, you pass the root to it as in this program. But when the node is not NULL, it continues printing the tree as more data is left to print. But every time the node is not NULL, the line traverse (node->left); calls the function once again before printing the node. Thus I do not understand how the whole tree gets printed. It would be helpful if someone could explain.
Let's take this binary tree as an example.
binary tree
How the whole tree gets printed?
Each time we call traverse function, we will print the data of *node.
Traverse process is a recursive process in which functions dealing with root node will call functions dealing with root's left-child and right-child. For example, traverse(15) will call traverse(5) and traverse(16), and traverse(5) will call traverse(3) and traverse(12).
Recuration ends with leaf nodes and every node is visited and printed.
Why the result is in-order?
In each call of void traverse(struct treeNode *node), we could regard *node as the root of a subtree. Following codes mean data of *node won't be printed until recurse of its left-child returns.
traverse(node->left);
printf("%3d", node->data);
traverse(node->right);
And traverse(node->left) returns only when its left-child and right-child are traversed, childs of node->left will also printed before *node. So, all nodes in left sub-tree of *node will be printed before *node, and all nodes in right sub-tree of *node will be printed after it.
For example, traverse(12) calls traverse(10) before print 12, traverse(10) calls traverse(6) and traverse(6) calls traverse(7). Since 7 is a leaf node, traverse(7), traverse(6) and traverse(10) returns in order. Then traverse(12) print 12 and calls traverse(13).
We could get in-order result of 6 7 10 12 13

Not deleting node with two children

When deleting a node with two children from my binary tree of "products", rather than replacing the root to delete with it's left child's most right ancestor and then deleting that descendant, it is simply just replacing that root's value with ancestors value. I have called "free()" on that ancestor but that doesn't seem to work. So what I am left with is two nodes of the same value.
My code:
#include <stdio.h>
#include <stdlib.h>
//Structures
typedef struct Node{
void *dataPtr;
struct Node *left;
struct Node *right;
}node;
typedef struct Product
{
int ProductCode;
char ProductName[30];
int QuantityOnHand;
double ProductCost;
double ProductRetail;
char ProductLocationCode[7];
}product;
//functions
int compareID(void *ptr1, void *ptr2)
{
int temp;
if (((product *)ptr1)->ProductCode > ((product *)ptr2)->ProductCode)
temp = 1;
else
if (((product *)ptr1)->ProductCode < ((product *)ptr2)->ProductCode)
temp = -1;
else
temp = 0;
return temp;
}
void insert(node ** root, node** val, int(*f)(void*,void*)){
if (!(*root)) {
//initalize a temporary node
node *temp = NULL;
temp = (node *)malloc(sizeof(node));
//make both right and left nodes for temp to be NULL
temp->left = NULL;
temp->right = NULL;
temp->dataPtr = (*val)->dataPtr;//store value you were looking for in temp
*root = temp;// root is now the temporary node
return;//end of function.
}
int result = f((*root)->dataPtr, (*val)->dataPtr);
if (result == 1) {//if the value is less than the current root node, go to the left connecting node
insert(&(*root)->left, &(*val), f);
}
else if (result == -1) {//if the value is more than the current root node, go to the right connecting node
insert(&(*root)->right, &(*val), f);
}
}
struct Node* deleteNode(struct Node *root, void *ptr, int(*cptr)(void*, void*))
{
struct Node *temp;
if (cptr(ptr, root->dataPtr) == 0)
{
if (root->left == NULL && root->right == NULL)//no children
{
free(root);
return NULL;
}
if (root->left != NULL && root->right == NULL)//left child
{
temp = root->left;
free(root);
return temp;
}
if (root->left == NULL && root->right != NULL)//right child
{
temp = root->right;
free(root);
return temp;
}
else //two children
{
struct Node* pred = root->left;//go left one of the node you're trying to delete
while (pred->right != NULL){//now get further right ancestor of that node
pred = pred->right;
}
root->dataPtr = pred->dataPtr; //make the original node the value of that right ancestor
return pred;//return that ancestor to delete it
}
}
else
{
int val = cptr(ptr, root->dataPtr);
if (val < 0)
{
root->left = deleteNode(root->left, ptr, cptr);
return root;
}
else
{
root->right = deleteNode(root->right, ptr, cptr);
return root;
}
}
}
void readData(struct Node** vptr, FILE *fp){
product* ptr = (product *)malloc(sizeof(product));
if (fp == stdin){
printf("Enter Product Code: ");
fscanf(fp, "%d", &(ptr->ProductCode));
fflush(stdin);
printf("Enter Name: ");
fscanf(fp, "%30[^\n]", ptr->ProductName);
fflush(stdin);
printf("Enter Quantity: ");
fscanf(fp, "%d", &(ptr->QuantityOnHand));
printf("Enter Cost: ");
fscanf(fp, "%lf", &(ptr->ProductCost));
fflush(stdin);
ptr->ProductRetail = (ptr->ProductCost / 0.7);
printf("Enter Location: ");
fscanf(fp, "%6[^\n]", &(ptr->ProductLocationCode));
fflush(stdin);
}
else{
fscanf(fp, "%d %29[^\n] %d %lf %6[^\n]", &(ptr->ProductCode), ptr->ProductName, &ptr->QuantityOnHand, &ptr->ProductCost, &ptr->ProductLocationCode);
ptr->ProductRetail = (ptr->ProductCost / 0.7);
}
(*vptr)->dataPtr = ptr;
}
int main()
{
int i = 0;
struct Node *newNode, *temp;
struct Node *root = NULL;
int(*compPtr)(void *, void *) = compareID;
for(i; i < 3; i++){
newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->left = newNode->right = NULL;// missing this operation.
readData(&newNode, stdin); // this function call was missing.
insert(&root, &newNode, compPtr);
}
temp = (struct Node *)malloc(sizeof(struct Node));
temp->dataPtr = malloc(sizeof(struct Product));
printf("enter the product ID to delete : ");
fflush(stdin);
scanf("%d", &((struct Product *)temp->dataPtr)->ProductCode);
deleteNode(root, temp->dataPtr, compPtr);
free(temp->dataPtr);
free(temp);
return 0;
}
Why is this ancestor node not being freed from memory? What should I change in order to make sure it is deleted?
Your question and code are confusing at first because you use the word "ancestor" when you mean "descendant." Child nodes are descendants. Ancestors are those that come before.
The problem appears to be that you're returning the descendant rather than deleting it. In all the other cases, you're deleting the root and returning the new node. In the case that's causing you trouble, you're not deleting any node. Instead, you're returning the left child's rightmost descendant. The code that calls deleteNode replaces the node to be deleted with the node that is returned.
In this case you need to return the root after deleting the node whose value replaced the root's value. But before you can delete that descendant node, you have to remove the link from that node's parent.
I think the code you want is:
//go left one of the node you're trying to delete
struct Node* parent = root;
struct Node* pred = root->left;
//now get further right descendant of that node
while (pred->right != NULL){
parent = pred;
pred = pred->right;
}
//make the original node the value of that right descendant
root->dataPtr = pred->dataPtr;
// unlink that node from its parent
if (parent == root)
parent->left = NULL;
else
parent->right = NULL;
free(pred);
return root; //return the root node

Resources