Recursive code for searching max height of binary tree - c

I've created a tree using this code (this is outdated look at the bottom, problem updated):
struct node* buildTree() {
struct node* root = NULL;
root = insert(root, 2);
root = insert(root, 4);
root = insert(root, 10);
return(root);
}
Then tried to find max depth of that (functions Max and insert work properly), using this:
int maxHeight(struct node* p) {
if(p == NULL) {return 0;}
else{
int leftDepth = 1 + maxHeight(p->left);
int rightDepth = 1 + maxHeight(p->right);
return(Max(leftDepth, rightDepth));
}
}
And it shows me error like max depth is 3; I've compiled in C99 standard. I've found this and similar code in several places in the Internet, but here doesn't work, any ideas what's wrong? Thanks..
As suggested adding insert code:
struct node* insert(struct node* node, int data) {
if (node == NULL) {
return(newNode(data));
}
else {
if (data <= node->data) node->left = insert(node->left, data);
else node->right = insert(node->right, data);
return(node);
}
}
And newNode function:
struct node* newNode(int data) {
struct node* node = malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
Update:
New buildTree function:
struct node* buildTree() {
struct node* root = newNode(3);
root->left = newNode(2);
root->right = newNode(1);
return(root);
}

The code works but it looks like the tree you built is not what you meant, probably as you keep concatenating a new node to the previous node (and not to the single root).
Assuming the insert returns the node just created then your first add a tree node 2:
Tree: (2)
The you're adding a tree node 4 as a child of tree node 2:
Tree: (2)--(4)
Finally you're adding a tree node 10 as a child of tree node 4:
Tree: (2)--(4)--(10)
So as you can see the tree depth is 3 (including the root).

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

Is there anyway to use Insert function using recursion without passing parameter? Is there any other way to make this program more efficient?

Here I have coded the binary tree using recursion and is working perfectly fine but I want to know is there any way that I can use the insert function without passing parameter for the root Node(i.e. address of the root node)
Edit1: Reading the below comments I came to know in C there isn't another way to use the insert function without passing the parameter of root node, so my next question is there any other way to make this program more efficient ?
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *left;
struct Node *right;
};
struct Node *GetNewNode(int data)
{
struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
struct Node *Insert(struct Node *root, int data)
{
if (root == NULL)
{
root = GetNewNode(data);
}
else if (data <= root->data)
{
root->left = Insert(root->left, data);
}
else
{
root->right = Insert(root->right, data);
}
return root;
}
int main()
{
struct Node *root = NULL;
root = Insert(root, 15);
root = Insert(root, 13);
root = Insert(root, 14);
root = Insert(root, 12);
root = Insert(root, 11);
}
Your function is rather unusual in that it sometimes mutates state and sometimes creates a new tree. It would be cleaner to simply always modify the input. This can be done as follows:
typedef struct Node* Tree;
void insert(Tree* const root, int const data) {
if (*root == NULL) {
*root = GetNewNode(data);
} else if (data <= (*root)->data) {
insert(&(*root)->left, data);
} else {
insert(&(*root)->right, data);
}
}
Now, we note that this is a tail-recursive procedure. Thus, we can trivially rewrite the procedure as follows:
void insertIterative(Tree* root, int const data) {
while(*root) {
root = data <= (*root)->data ? &(*root)->left : &(*root)->right;
}
*root = GetNewNode(data);
}
This is a much more efficient function than your original one because your original function is needlessly non-tail recursive. If we want to replicate your original function's inputs and outputs, we can simply write
Tree Insert(Tree root, int const data) {
insertIterative(&root, data);
return root;
}
As many have noted in the comments, if a function depends on an input like root, it is the best practice to pass the input in to the function.

i tried insertion in BST tree using itteration but the output is incomplete. Where is might be the problem?

**I was doing insertion operation in BST using itteraton mechanism. I did inorder traversal using recursion for swift display of my tree and to know whether i am doing it right or wrong. However, the output is always 4 . I donot understand ummwhat might be the problem. Is my root not updating? **
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int data;
struct Node *left;
struct Node *right;
}node;
node *new(int data){ //create node
node *pw;
pw = (node *)malloc(sizeof(node *));
pw->data = data;
pw->left = NULL;
pw->right= NULL;
return pw;
}
node *insert(node *root, int data ){ //insert using itteration
node *pr;
pr = root;
if(root==NULL)
return new(data);
while(pr!= NULL){
if(data< pr->data){
if(pr->left==NULL){
pr->data = data;
pr=NULL;
}
else{
pr= pr->left;
}
}else if(data> pr->data){
if(pr->right==NULL){
pr->data = data;
pr=NULL;
}
else{
pr= pr->right;
}
}
}
return pr;
}
void inorder(node *root) {
if (root != NULL) {
// Traverse left
inorder(root->left);
// Traverse root
printf("%d -> ", root->data);
// Traverse right
inorder(root->right);
}
}
void main(){
node* root = NULL;
root = insert(root,5);
root = insert(root,6);
root = insert(root,4);
inorder(root); //inorder traversal for displaying tree
}
it seems like you are always changing the parent node's data instead of creating a new node to be the child of the parent node.
so instead of:
if(pr->left==NULL){
pr->data = data;
pr=NULL;
}
it needs to be:
if(pr->left==NULL){
pr->left = new(data);
break; /*you have inserted the node, a break will stop the loop*/
}
same change should be applied for the right if statement.
And further - insert has this return statement: return pr and that you save into root in the caller. However, root is only to be changed when root is NULL to start with. In other words: Returning pr is wrong.
Therefore do this change:
return pr; ---> return root;

Are dynamically allocated nodes of lists accessible throughout program?

I have created a linked list in C. I dynamically allocate memory as
'''
struct node* createNode(value) {
struct node* newNode =
malloc(sizeof(struct node));
newNode->data = value;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
struct node* insertLeft(struct node* root, int value) {
root->left = createNode(value);
return root->left;
}
int main() {
struct node* root = createNode(1);
insertLeft(root,12);
//Create more nodes
postorder(root);
}
void postorder(struct node* root) {
if (root == NULL) return;
postorder(root->left);
postorder(root->right);
printf("%d ->", root->data);
}
'''
Now the root node I am getting after insertion is of the newly inserted element.Because I return this new node. How come while traversing the top-most root is passed to postorder.
Also if I don't return this new node it should still exist in the memory so why return?
Now the root node I am getting after insertion is of the newly inserted element.Because I return this new node.
That's not the case. When you call insertLeft(), you don't assign its return value to anything. So root still points to the node with data == 1.

Level order traversal of binary search tree

I was trying to implement level order traversal of binary search tree using linked list implementation of queue.
I have checked the binary search tree implementation and it is fine.
The linked list implementation of queue is also correct.
Here i am trying to visit the node and enqueue its children to the queue.
and then use the pop function to actually visit the node.
This is being done via a recursive call in the end.
When i run the following code i am getting the output in different order.
// Trees
#include <stdio.h>
#include <stdlib.h>
//Node declaration for binary search tree
struct node
{
int data;
struct node *left;
struct node *right;
};
// LINKED LIST BASED IMPLEMENTATION OF QUEUE
struct qnode
{
struct node *data;
struct qnode *next;
};
struct qnode *head = NULL;
void insertq (struct node *); //This function enqueue node in the queue.
struct node *pop (); // dequeue function
//The function declaration for level order traversal.
void leorder ();
struct node *make (int);
struct node *insert (struct node *, int);
void
main ()
{
struct node *root = NULL;
root = insert (root, 10);
root = insert (root, 9);
root = insert (root, 8);
root = insert (root, 5);
root = insert (root, 2);
root = insert (root, 4);
root = insert (root, 3);
root = insert (root, 6);
root = insert (root, 7);
root = insert (root, 1);
insertq (root); //Insertion of first root.
leorder ();
}
//The program that makes nodes for the bst.
struct node* make(int x){
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->data = x;
temp->left = NULL;
temp->right = NULL;
return temp;
};
//The node insertion function.(BINARY SEARCH TREE)
struct node* insert(struct node* root,int x){
if(root == NULL){
root = make(x);
}
else{
if(x <= root->data){
root->left = insert(root->left,x);
}
else{
root->right = insert(root->right,x);
}}
return root;
}
// This function will insert node in the queue.
void insertq(struct node* x){
if(head == NULL){
struct qnode* temp = (struct qnode*)malloc(sizeof(struct qnode));
temp->data = x;
temp->next = NULL;
head = temp;
}
else{
struct qnode* temp = (struct qnode*)malloc(sizeof(struct qnode));
temp->data = x;
temp->next = head;
head = temp;
}
}
struct node* pop(){
struct node* r;
if(head == NULL){
return NULL;
}
else{
struct qnode* pt;
pt = head;
head = head->next;
r = pt->data;
free(pt);
return r;
}
}
// dequeue function.
struct node* pop(){
struct node* r;
if(head == NULL){
return NULL;
}
else{
struct qnode* pt;
pt = head;
head = head->next;
r = pt->data;
free(pt);
return r;
}
}
// Function to print tree in level order.
void leorder(){
struct node* popped;
popped = pop();
printf("%d ",popped->data);
if(popped != NULL){
if(popped->left != NULL){
insertq(popped->left);
}
if(popped->right != NULL){
insertq(popped->right);
}
leorder();
}
}
Right now, you insert at the head, and you remove at the head. This means you have a stack (last in, first out), not a queue (first in, first out).
Add a tail pointer, and remove from the opposite end that you add. If you add at the head, remove from the tail, or vice-versa.

Resources