Implementing a binary search tree - c

I'm trying to implement a binary search tree that holds an inventory of ordered stock. The stocked item attributes are stored in nodes as such:
typedef struct item item_t;
struct item{
char name;
int price;
int quantity;
item_t *left;
item_t *right;
};
The idea is to prompt a user to enter the above attributes, and then add the entered item to a node. This is what I've written so far:
item_t *root = NULL;
item_t *current_leaf = NULL;
void prompt_user(){
/*
In here contains the code that prompts the user for the item attributes
and stores it in a variable called input
*/
insert_node(input);
}
void insert_node(char *input){
/*If tree doesnt have a root...*/
if (root == NULL){
/*Create one...*/
*root = create_node(input);
}
else{
item_t *cursor = root;
item_t *prev = NULL;
int is_left = 0;
int comparison;
while(cursor != NULL){
/*comparison will be 1 is the key of input is less than the key
of the cursor, and 2 otherwise...*/
comparison = compare(input, cursor);
prev = cursor;
if(comparison == 1){
is_left = 1;
cursor = cursor->left;
}
else if (comparison == 2){
is_left = 0;
cursor = cursor->right;
}
}
if(is_left){
*prev->left = create_node(input);
current_leaf = prev->left;
}
else{
*prev->right = create_node(input);
current_leaf = prev->right;
}
}
}
item_t create_node(char *input){
item_t *new_node = (item_t*)malloc(sizeof(item_t));
if (new_node == NULL){
printf("Out of memory. Shutting down.\n");
exit(EXIT_FAILURE);
}
/*Add data to the node...*/
update_item(input, new_node);
new_node->left = NULL;
new_node->right = NULL;
current_leaf = new_node;
return *new_node;
}
I want root to always be pointing to the first item ever entered, and current_leaf to be pointing to the last item processed. compare returns 1 if the item being processed (input) is less than the last processed item (current_leaf). update_item is what sets the data for the new nodes (leaves).
The above isn't fully complete, but it's what I'm up to at the moment. I'm struggling to work out how to write add_node and how to keep current_leaf updated correctly.
EDIT: revised my code

It is an example of BST. Structure of the tree is:
typedef struct node{
int data;
struct node *left, *right;
}node;
Letting root global is not a good idea, so it is better to declare it inside main() and the insert() will be called from main like this:
int main()
{
int n,data;
node *root=NULL;
printf("How many elements? ");
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&data);
insert(&root,data);
}
inorder(root);
return 0;
}
This is the code for insertion and traversing a binary tree-
void insert(node **root, int data)
{
node *n1,*temp;
n1=(node *)malloc(sizeof(node));
n1->data=data;
n1->left=n1->right=NULL;
if(!(*root))
{
(*root)=n1;
//printf("Node inserted\n");
return;
}
temp=*root;
while(temp!=NULL)
{
if(temp->data<temp->data)
{
//printf("To the right");
if(temp->right==NULL)
{
temp->right=n1;
break;
}
else
temp=temp->right;
}
else if(temp->data>=n1->data)
{
if(temp->left==NULL)
{
temp->left=n1;
break;
}
else
temp=temp->left;
}
}
//printf("Inserted\n");
}
void inorder(node *root)
{
if(root==NULL)
return;
inorder(root->left);
printf("item: %d",root->data);
inorder(root->right);
}
The searching will be same almost same logic as insert, please develop it yourself.

Related

Binary Tree implementation on C

I am trying to implement tree in C but the thing is whenever i try to traverse it, it only shows the first three nodes of the tree and the rest are lost. like, if i enter 100, 200, 300, 400, 500, 600, 700 then only 100 ,200, 300 will be in the output. I think the problem is with insert function but i just can't figure it out.
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *prev;
struct node *next;
};
typedef struct node list;
list *head, *tail, *current, *newn;
void inorder(struct node *t)
{
if(t != NULL)
{
inorder(t->prev);
printf("%d->",t->data);
inorder(t->next);
}
}
struct node * insert(int key, struct node *t)
{
if(t == NULL)
{
t = (list*)malloc(sizeof(list));
t->data = key;
t->prev = NULL;
t->next = NULL;
}
else if(t->prev == NULL)
{
t->prev = insert(key,t->prev);
}
else if(t->next == NULL)
{
t->next = insert(key,t->next);
}
return(t);
}
int main()
{
int x=1, y, z=1;
current = (list*)malloc(sizeof(list));
printf("Enter data:");
scanf("%d",&current->data);
current->next = NULL;
current->prev = NULL;
head = current;
while(z == 1)
{
printf("Enter data:");
scanf("%d",&y);
current = insert(y,current);
printf("want to insert more:");
scanf("%d",&z);
}
printf("\nInorder Traversal:");
newn = head;
inorder(newn);
}
only 100 ,200, 300 will be in the output.
at Insert function
if(t == NULL)
{
...
}
else if(t->prev == NULL)
{
...
}
else if(t->next == NULL)
{
...
}
return(t);
Because it is
When t, t->prev and t->next are not all NULL
Nothing (that is, inserting) is done.
When adding conditions and recursive calls like
else if(t->prev->prev == NULL)
{
t->prev->prev = insert(key, t->prev->prev);
}
Insertion of the node is done, but since growth becomes like depth-first search, the growth of the tree becomes biased.
So, as an approach you need to search for the next insertion point like breadth first search.
I think there are some methods,
As a method I propose, it is a way to keep it as a pool when creating a NULL node rather than searching.
A concrete implementation using a queue as a node pool is as follows(Please note that many checks are omitted And using global variables).
#include <stdio.h>
#include <stdlib.h>
struct node{
int data;
struct node *prev;
struct node *next;
};
typedef struct node list;
void inorder(struct node *t){
if(t != NULL){
inorder(t->prev);
printf("%d->",t->data);
inorder(t->next);
}
}
//node of queue
typedef struct null_node {
list **nodepp;
struct null_node *next;
} node_pool;
//queue
typedef struct queue {
node_pool *head;
node_pool *tail;
} queue;
//enqueue
void push(queue *q, list **nodepp){
node_pool *np = malloc(sizeof(*np));
np->nodepp = nodepp;
np->next = NULL;
if(q->head == NULL){
q->tail = q->head = np;
} else {
q->tail = q->tail->next = np;
}
}
//dequeue
list **pop(queue *q){
node_pool *head = q->head;
if(head == NULL)
return NULL;
q->head = q->head->next;
if(q->head == NULL)
q->tail = NULL;
list **nodepp = head->nodepp;
free(head);
return nodepp;
}
void clear_queue(queue *q){
while(pop(q));
}
list *Head;
queue Q;
struct node *insert(int key, struct node *root){
list *t = malloc(sizeof(*t));
t->data = key;
t->next = t->prev = NULL;
push(&Q, &t->prev);//enqueue a NULL node
push(&Q, &t->next);
if(root == NULL){
return t;
}
list **null_nodep = pop(&Q);//dequeue the node
*null_nodep = t;//Replace with new node
return root;
}
int main(void){
int /*x=1, unused x*/ y, z=1;
Head = NULL;
while(z == 1){
printf("Enter data:");
scanf("%d",&y);
Head = insert(y, Head);
printf("want to insert more:");
scanf("%d",&z);
}
printf("\nInorder Traversal:");
inorder(Head);
clear_queue(&Q);//Discard queued nodes
}

Inserting into binary search tree using recursion in C

I was making a program to make a binary search tree which takes input from the user.
I have deliberately shown two search functions in my code below.
Problem: The search function2 works correctly but the search function1 does not work correctly (when used after commenting the other each time).
Why is it so?
I tried doing the dry run and building the recursion stack, which works fine as per me. But somehow I think the search function 1 is not able to make that linking in the linked list to insert the element. That is the reason I am not getting the right output when I try to do the inorder traversal
Any help will be really appreciated!
#include <stdio.h>
#include <stdlib.h>
struct node{
int data;
struct node *left;
struct node *right;
};
struct node *root = NULL;
struct node *newNode(int data){
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->data = data;
temp->left = NULL;
temp->right = NULL;
return temp;
}
//SEARCH FUNCTION 1: this does not work correctly
void search(struct node *t,int data){
if(t){
if(data > t->data){
search(t->right,data);
}else{
search(t->left,data);
}
}else{
t = newNode(data);
}
}
//SEARCH FUNCTION 2: this works fine and inserts the element correctly
void search(struct node *t, int data){
if(data < t->data && t->left != NULL){
search(t->left, data);
}else if(data < t->data && t->left == NULL){
t->left = newNode(data);
}else if(data > t->data && t->right != NULL){
search(t->right,data);
}else{
t->right = newNode(data);
}
}
void insertNode(int data){
if(!root){
root = newNode(data);
return;
}
search(root, data);
}
void inorder(struct node *t){
if(t){
if(t->left){
inorder(t->left);
}
printf("%d ->", t->data);
if(t->right){
inorder(t->right);
}
}
}
int main(){
int step, data;
while(1){
printf("1. Insert element\n");
printf("2. Print tree\n");
scanf("%d",&step);
switch(step){
case 1: printf("enter element to be inserted\n");
scanf("%d",&data);
insertNode(data);
break;
case 2:inorder(root);
printf("\n");
break;
}
}
return 0;
}
The problem is that the statement t = newNode(data) assigns to a local variable, so the result is lost immediately after returning from the function.
In this case one solution is double indirection, as you don't just want to modify the thing a pointer points to, but the pointer itself.
void search(struct node **pt,int data)
{
struct node *t = *pt;
if (t) {
if (data > t->data) {
search(&t->right,data);
} else {
search(&t->left,data);
}
} else {
*pt = newNode(data);
}
}
1st search function:
void search(struct node *t,int data){
...
t = newNode(data);
}
but then in the 2nd search function you do:
void search(struct node *t, int data){
...
t->right = newNode(data);
}
which will remember the assignment, while the first will not, since when you are going to recurse, the changes will be lost.
You see in the 2nd case, you are assign what newNode() returns to data member of a struct that is a pointer, while the struct is passed a pointer in this function. However, in the 1st case, you assign the result in a struct that is passed by one pointer only. If a double pointer would be used, things would be differently.

Linked list- find_node_data

I have previously posted about this same topic. I am self-learning data structures using MIT Open Courseware. I'm doing the 6.S096-Introduction to C/C++ course and attempting the fourth assignment.
It is based on binary search trees and I gave it a try. I wanted to print the values for debugging but kept getting different executions each time.
One time, the cycle doesn't complete and the other time, it goes on to infinity. The debugging block also relates to the other function(find_node_data) I have to complete. So if I can figure what's wrong here, I can easily finish the find_node_data. I have commented a few things to see if it affects anything. What am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int node_id;
int data;
struct node* left;
struct node* right;
}node;
///*** DO NOT CHANGE ANY FUNCTION DEFINITIONS ***///
// Declare the tree modification functions below...
node* newNode(int data,int node_id){
node* new_node = (node*) malloc(sizeof(node));
new_node->data = data;
new_node->node_id= node_id;
new_node->right= new_node->left=NULL;
return new_node;
}
node* insert_node(node* root, int node_id, int data) {
if(root==NULL)
return newNode(data,node_id);
else{
node* cur;
if(node_id<root->node_id){
cur=insert_node(root->left,data,node_id);
root->left=cur;
}
else if(node_id>root->node_id){
cur=insert_node(root->right,data,node_id);
root->right=cur;
}
}
return root;
}
// Find the node with node_id, and return its data
/*int find_node_data(node* root, int node_id) {
node* current;
for( current = root->; current->next!=NULL;
current= current->next){
if(current->data == data) return current;
}
return NULL;
}
*/
int main() {
/*
Insert your test code here. Try inserting nodes then searching for them.
When we grade, we will overwrite your main function with our own sequence of
insertions and deletions to test your implementation. If you change the
argument or return types of the binary tree functions, our grading code
won't work!
*/
int T,data,node_id;
printf("Print yo cases");
scanf("%d", &T);
node* root = NULL;
while(T-->0){
printf("Type yo numnums no. %d:",T);
scanf("%d %d",&data,&node_id);
root=insert_node(root,data,node_id);
}
node *lol;
node *king;
for(lol=root;lol->left!=NULL;lol=lol->left){
//for(king=root;king->right!=NULL;king=king->right){
printf("executed!\n");
printf("%d ",lol->node_id);//,king->node_id);
//}
}
return 0;
}
To find the node_data you can use recursion to find the node.
node* find_node_data(node *root, int node_id) {
if (root == NULL)
return NULL;
else if (root->node_id == node_id)
return root;
else {
node *left = find_node_data(root->left, node_id);
return left? left: find_node_data(root->right, node_id);
}
}
And then get the data for the node e.g. get the data for node with node_id 42:
printf("node data %d", find_node_data(root, 42)->data);
Full program below (I can't guarantee its correctness but maybe you can?)
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int node_id;
int data;
struct node *left;
struct node *right;
} node;
///*** DO NOT CHANGE ANY FUNCTION DEFINITIONS ***///
// Declare the tree modification functions below...
node *newNode(int data, int node_id) {
node *new_node = (node *) malloc(sizeof(node));
new_node->data = data;
new_node->node_id = node_id;
new_node->right = new_node->left = NULL;
return new_node;
}
node *insert_node(node *root, int data, int node_id) {
if (root == NULL)
return newNode(data, node_id);
else {
node *cur;
if (node_id < root->node_id) {
cur = insert_node(root->left, data, node_id);
root->left = cur;
}
else if (node_id > root->node_id) {
cur = insert_node(root->right, data, node_id);
root->right = cur;
}
}
return root;
}
// Find the node with node_id, and return its data
/*
int find_node_data_old(node *root, int node_id) {
node *current;
for (current = root->; current->next != NULL;
current = current->next) {
if (current->data == data) return current;
}
return NULL;
}*/
node* find_node_data(node *root, int node_id) {
if (root == NULL)
return NULL;
else if (root->node_id == node_id)
return root;
else {
node *left = find_node_data(root->left, node_id);
return left? left: find_node_data(root->right, node_id);
}
}
void print(node *np) {
if (np) {
print(np->left);
printf("(%d, %d)", np->node_id, np->data);
print(np->right);
}
}
int main() {
/*
Insert your test code here. Try inserting nodes then searching for them.
When we grade, we will overwrite your main function with our own sequence of
insertions and deletions to test your implementation. If you change the
argument or return types of the binary tree functions, our grading code
won't work!
*/
int T, data, node_id;
printf("Print yo cases");
scanf("%d", &T);
node *root = NULL;
while (T-- > 0) {
printf("Type yo numnums no. %d:", T);
scanf("%d %d", &data, &node_id);
root = insert_node(root, data, node_id);
}
node *lol;
node *king;
for (lol = root; lol->left != NULL; lol = lol->left) {
//for(king=root;king->right!=NULL;king=king->right){
printf("executed!\n");
printf("%d ", lol->node_id);//,king->node_id);
//}
}
print(root);
printf("\n");
printf("node data %d", find_node_data(root, 42)->data);
return 0;
}
Test
Print yo cases3
Type yo numnums no. 2:22 42
Type yo numnums no. 1:21 41
Type yo numnums no. 0:20 40
executed!
42 executed!
41 (40, 20)(41, 21)(42, 22)
node data 22
You may also use Jonathan Leffler's improved recursion to find the node:
node *find_node_data2(node *root, int node_id) {
if (root == NULL)
return NULL;
else if (root->node_id == node_id)
return root;
else if (root->node_id > node_id)
return find_node_data(root->left, node_id);
else
return find_node_data(root->right, node_id);
}
Both functions return the correct values as seen in the second test.
int main() {
/*
Insert your test code here. Try inserting nodes then searching for them.
When we grade, we will overwrite your main function with our own sequence of
insertions and deletions to test your implementation. If you change the
argument or return types of the binary tree functions, our grading code
won't work!
*/
int T, data, node_id;
printf("Print yo cases");
scanf("%d", &T);
node *root = NULL;
while (T-- > 0) {
printf("Type yo numnums no. %d:", T);
scanf("%d %d", &data, &node_id);
root = insert_node(root, data, node_id);
}
node *lol;
node *king;
for (lol = root; lol->left != NULL; lol = lol->left) {
//for(king=root;king->right!=NULL;king=king->right){
printf("executed!\n");
printf("%d ", lol->node_id);//,king->node_id);
//}
}
print(root);
printf("\n");
printf("node data %d\n", find_node_data(root, 42)->data);
printf("node data find_node_data2 %d", find_node_data2(root, 42)->data);
return 0;
}
Test 2
Print yo cases3
Type yo numnums no. 2:11 12
Type yo numnums no. 1:13 14
Type yo numnums no. 0:20 42
(12, 11)(14, 13)(42, 20)
node data 20
node data find_node_data2 20

Binary Search Tree in C Segmentation Fault

I've been trying to implement a simple binary search tree in C just as an exercise. I can insert elements into the tree, but at certain points (I haven't been able to figure out where) I'm getting a segmentation fault.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
struct node {
struct node *left;
struct node *right;
int key;
};
void insert(struct node *treeNode, int key);
void outputTree(struct node *root);
int main(){
//Store how many numbers the user will enter
printf("How many numbers will you enter? > ");
int numNumbers;
scanf("%d", &numNumbers);
//Create a root node
struct node root;
root.key = -1; //-1 Means the root node has not yet been set
root.right = NULL;
root.left = NULL;
//Now iterate numNumbers times
int i;
for(i = 1; i <= numNumbers; ++i){
int input;
scanf("%d", &input);
insert(&root, input);
}
outputTree(&root);
return 0;
}
void insert(struct node *treeNode, int key){
//First check if the node is the root node
if((*treeNode).key == -1){
printf("Root node is not set\n");
(*treeNode).key = key; //If the root node hasn't been initialised
}
else {
//Create a child node containing the key
struct node childNode;
childNode.key = key;
childNode.left = NULL;
childNode.right = NULL;
//If less than, go to the left, otherwise go right
if(key < (*treeNode).key){
if((*treeNode).left != NULL){
printf("Left node is not null, traversing\n");
insert((*treeNode).left, key);
}
else {
printf("Left node is null, creating new child\n");
(*treeNode).left = &childNode;
}
}
else {
//Check if right child is null
if((*treeNode).right != NULL){
printf("Right node is not null, traversing...\n");
insert((*treeNode).right, key);
}
else {
printf("Right node is null, creating new child\n");
(*treeNode).right = &childNode;
}
}
}
}
void outputTree(struct node *root){
//Traverse left
if((*root).left != NULL){
outputTree((*root).left);
}
printf("%d\n", (*root).key);
if((*root).right != NULL){
outputTree((*root).right);
}
}
As of writing this question, I've just had the thought, are the child nodes being created on the stack, so when the recursive calls return, the references in the tree are pointing to a struct that no longer exists?
What is wrong here?
Thank you
You create childs node on the stack by static allocation. When the insert method is finished, the child reference become invalid.
You should use dynamic allocation with malloc.
struct node *new_node(int key, struct node *left, struct node *right) {
struct node *this = malloc(sizeof *this);
this->key = key;
this->left = left;
this->right = right;
return this;
}
don't forget to free all of your allocations with the free function.
edit :
so to create the root just use
struct node *root = new_node(-1, NULL, NULL);

Delete a node from a linked list after finding it

I'm having trouble deleting a node from a linked list by inputting the telephone number of the record. This is the code that is supposed to do this:
typedef struct record
{
char name[20];
char surname[20];
char telephone[20];
}Record;
typedef struct node
{
Record data;
struct node *next;
}Node;
Node *head = NULL;
void delete() {
Node *n = head;
Node* previous = NULL;
Node *next = n;
.
.
. (here i wrote the code to enter the number (stored in telNumber[20])and find the record containing the number
while (n != NULL) {
if (&n->data.telephone == telNumber) {
if (previous == NULL) {
n = n->next;
free(head);
}
else {
previous->next = n->next;
free(n);
n = previous->next;
}
}
else {
previous = n;
n = n->next;
}
}
printf("You have successfully deleted the telephone record");
The record still remains there.
This:
if (&n->data.telephone == telNumber)
is not how to compare strings for equality in C. That will compare the addresses, which will never match.
It should be:
if (strcmp(n->data.telephone, telNumber) == 0)

Resources