I am not too good at making trees and I totally screw up recursion. However, I attempted to make a program to insert and display data into the tree.
The problem is that it crashes after inserting into the root node and I do not know why. The tree is not too big. Just 10 int.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct node{
int data;
struct node * left;
struct node * right;
};
void insert(struct node * root,int num){
printf("Insert called for num:%d\n",num);
if(root == NULL){
root = (struct node *)malloc(sizeof(struct node));
root->data = num;
}else if(num > root->data){ // Number greater than root ?
insert(root->right,num); // Let the right sub-tree deal with it
}else if(num < root->data){// Number less than root ?
insert(root->left,num);// Let the left sub-tree deal with it.
}else{
// nothing, just return.
}
}
void display(struct node * root){ // Inorder traversal
if(root->left!=NULL){ // We still have children in left sub-tree ?
display(root->left); // Display them.
}
printf("%d",root->data); // Display the root data
if(root->right!=NULL){ // We still have children in right sub-tree ?
display(root->right); // Display them.
}
}
int main(int argc, char *argv[]) {
int a[10] = {2,1,3,5,4,6,7,9,8,10};
int i;
struct node * tree;
for(i = 0; i < 10;i++){
insert(tree,a[i]);
}
printf("Insert done");
return 0;
}
Can someone please tell me where I went wrong ?
I know it is frowned upon to ask people to review your code on Stack but sometimes pair programming works :p
Update:
After setting struct node * tree = NULL;, the insert() method works well. The display() causes program to crash.
in your
int main(int argc, char *argv[]) {
// ...
struct node * tree;
// what is the value of tree at this line?
for(i = 0; i < 10;i++){
insert(tree,a[i]);
}
// ...
}
what does "tree" point to at the line marked?
Related
In one of the C exercises I had to create a function for binary tree traversal with a given depth.
My first thought was to use a for loop (traverse_preorder_bad). Finally, I could complete the task with a variable initialization + if (traverse_preorder_working), but I am still struggling to understand why the for solution didn't work.
Could someone explain me the difference? Is there an elegant solution?
Code on Ideone
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
const int RANGE = 1000;
typedef struct node_t
{
int data;
struct node_t *left;
struct node_t *right;
} node_t;
node_t *node_new(int data);
node_t *node_insert(node_t *tree, int data);
void traverse_preorder_working(node_t *tree, int depth);
void traverse_preorder_bad(node_t *tree, int depth);
int main(int argc, char *argv[])
{
node_t *tree = NULL;
// Random seed
srand((unsigned) time(NULL));
// Create the root node
tree = node_new(rand() % RANGE);
node_insert(tree, 5);
node_insert(tree, 1);
printf("Expected output:\n");
traverse_preorder_working(tree, 10);
printf("Bad output:\n");
traverse_preorder_bad(tree, 10);
return 0;
}
node_t *node_new(int data)
{
node_t *tree;
tree = malloc(sizeof(*tree));
tree->left = NULL;
tree->right = NULL;
tree->data = data;
return tree;
}
node_t *node_insert(node_t *tree, int data)
{
if (!tree)
return node_new(data);
if (data == tree->data)
return tree;
if (data < tree->data)
tree->left = node_insert(tree->left, data);
else
tree->right = node_insert(tree->right, data);
return tree;
}
void traverse_preorder_working(node_t *tree, int depth)
{
int i;
if (!tree)
return;
printf("%d\n", tree->data);
i = 1;
if (tree->left && i <= depth)
{
traverse_preorder_working(tree->left, depth - i);
i++;
}
i = 1;
if (tree->right && i <= depth)
{
traverse_preorder_working(tree->right, depth - i);
i++;
}
}
void traverse_preorder_bad(node_t *tree, int depth)
{
if (!tree)
return;
printf("%d\n", tree->data);
for (int i = 1; tree->left && i <= depth; i++)
traverse_preorder_bad(tree->left, depth - i);
for (int i = 1; tree->right && i <= depth; i++)
traverse_preorder_bad(tree->right, depth - i);
}
The problem is that traverse_preorder_working is correctly recursive, when visiting a node you call traverse_preorder_working recursively on the left subtree (and then right)
Instead traverse_preorder_bad is still recursive but it makes no sense, when you visit a node you then call traverse_preorder_bad n-times on the same subtree with a different depth.
If you check invocation tree for something like:
a
/ \
b c
/ \ / \
d e f g
You can see that traverse_preorder_working(a,5) goes traverse_preorder_working(b,4), traverse_preorder_working(d,3) .. while other function goes
traverse_preorder_bad(a,5),
traverse_preorder_bad(b,4), visit subtree
traverse_preorder_bad(b,3), visit subtree
traverse_preorder_bad(b,2), visit subtree
traverse_preorder_bad(b,1), visit subtree ...
from the same level of recursion, which means that each node will be visited multiple times with different depth limits; this doesn't happen in the first correct version.
If each invocation of traverse_preorder_bad should visit a node and start visiting both subtrees but inside the code you call visit recursively more than twice (which is the case, since you have a loop) then something is wrong.
The "for" version make no sense. You only want to print the tree for a given node once, so you should only call traverse on each node once.
Additionally, based on one of your comments in your post, I think you have some misunderstandings about your working function.
You have multiple checks for whether the tree is null (both as the current tree or as its children)
i ever only has a value of one while it is being used. You could simplify to
void traverse_preorder_working(node_t *tree, int depth){
if(!tree || depth <= 0){
return;
}
printf("%d\n", tree->data);
traverse_preorder_working(tree->left, depth - 1);
traverse_preorder_working(tree->right, depth - 1);
}
All of the checks to see if we not should explore a node - either because it doesn't exist or it is too deep - are done only once (at the start of the function), and not repeated twice for each child. No i variable that does nothing.
The elegant solution here (without recursion) is Morris Traversal. The idea is to add indirection edge from the left subtree's rightmost node to the current node.
The full explanation of the algorithm is here: http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion-and-without-stack/
Of course you can modify this algorithm not to go deeper then you current depth.
I am going through the cs50x course, doing speller check program. In my fourth implementation of this program I've ran into malloc problem.
This time I decided to implement a binary tree.
I've read a lot of threads about this problem and checked my code for several times, but I still can't understand what I'm doing wrong.
Problem appears in the recursive function that loads dictionary into ram.
#include <stdbool.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "dictionary.h"
// standart node of the trie
typedef struct node
{
char word[LENGTH + 1];
struct node* less;
struct node* more;
}
node;
// Function definitions
void unload_node(node* pr_node);
void ld_bin_tree(int min, int max, node* node);
bool check_word(char* lword, node* parent);
// Global variables
// root of the tree
node* root;
FILE* dict;
//size of dictionary
int dict_size = 0;
bool load(const char* dictionary)
{
// open dictionary file
dict = fopen(dictionary, "r");
int nwords = 0;
int min = 0;
int max = 0;
root = malloc(sizeof(node));
//if file wasn't open
if(dict == NULL)
{
printf("Error opening ditionary file!");
return false;
}
// tmp storage for read word
char buffer[LENGTH + 1];
// count words in the dictionary
while(fscanf(dict, "%s", buffer) > 0)
{
nwords++;
}
max = nwords;
rewind(dict);
ld_bin_tree(min, max, root);
// close file
fclose(dict);
return false;
}
/*
* Recursion function to fill in binary tree
*/
void ld_bin_tree(int min, int max, node* node)
{
// tmp word holder
char buffer[LENGTH + 1];
// next mid value
int mid = (min + max) / 2;
// if mid == 0 then the bottom of the brunch reached, so return
if(max - min < 2)
{
if(min == 0)
{
fscanf(dict, "%s", node->word);
dict_size++;
return;
}
return;
}
// go through the dict to the mid string
for(int i = 0; i <= mid; i++)
{
fscanf(dict, "%s", buffer);
}
// fill in word
strcpy(node->word, buffer);
// go at the beginning of the dict
rewind(dict);
// fill in input node
// fill in new children nodes
struct node* new_node = malloc(sizeof(node));
node->less = new_node;
// send lesser side
ld_bin_tree(min, mid, node->less);
new_node = malloc(sizeof(node));
node->more = new_node;
// send greater side
ld_bin_tree(mid, max, node->more);
dict_size++;
return;
}
I've tried to get this error using valgrind but it gives me a lot of warnings about reading and writing in unappropriated memory blocks. But because I'm not very good with programming yet, this warnings didn't give me a clue of what's happening.
So I'm asking for more precise help, if it's possible. Thank you in advance.
Other parts of the speller program may be found here:
https://www.dropbox.com/sh/m1q1ui2g490fls7/AACnVhjjdFpv1J0mUUhY2uV2a?dl=0
In function ld_bin_tree() you have
struct node* new_node = malloc(sizeof(node));
Here node is a pointer not an object of type struct node.
You have
node *node;
So the global definition of node is being overwritten which makes it a pointer.
So you are not allocating memory for your whole structure. You should have
struct node* new_node = malloc(sizeof(struct node));
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct node_{
int val;
struct node_ *left;
struct node_ *right;
}node;
node* insert(node* root,int val);
void inorder(node* root);
int main(void)
{
int i;
int item;
node* root = NULL;
srand(time(NULL));
for( i = 0; i < 10; i++)
{
item = rand()%15;
insert(root,item);
}
inorder(root);
return 0;
}
node* insert(node* root,int val)
{
if(root == NULL)
{
root = malloc(sizeof(node));
if(root!= NULL)
{
(root)->val = val;
(root)->left = NULL;
(root)->right = NULL;
}
else
printf("%d not inserted. No memory available.\n",val);
}
else
{
if(val < (root)->val)
{
insert((root->left),val);
}
if(val>root->val)
{
insert(((root)->right),val);
}
}
}
void inorder(node* root)
{
printf("%p",root);
if(root != NULL)
{
inorder(root->left);
printf("%3d",root->val);
inorder(root->right);
}
}
I am trying to create a binary tree and print out the values in order. However when I run this code the printf of the address prints out nil obviously meaning that my tree is empty so the printf and recursion below does not run. I cannot figure out where I went wrong, any suggestions or answers would be appreciated because I can't figure out why the root would be null after calling all of those inserts in main.
You pass root as a parameter to insert() (which says it is going to return something but doesn't). Inside insert you malloc your node and assign it to the local variable root. Nothing you ever do makes it out of the insert function.
Try returning something from insert, or using a global root.
As #JoshuaByer hints in the comments below, another approach is to make your insert method "pass by reference" so it can effectively modify what was passed to it.
void insert(node** rootp,int val)
{
if(*rootp == NULL)
{
*rootp = malloc(sizeof(node));
}
/* and so on */
If you don't understand what this is saying, google "Pass by reference in C" and I'm positive you'll get some good information.
In main() after declaring and initializing root (node* root = NULL;) you're never assigning it. In order to fix you should probably change the lin insert(root,item); to root = insert(root,item);.
Also note that although insert is defined as returning node * it does not return any value.
Following is my code for building a simple tree. The approach I'm using here is that if a particular node is at index n in the arr[] array, then it has it's left child at index 2*n+1 and right child at 2*n+2 in the same arr[] array. And then I'm doing an inorder traversal. However, I'm getting an infinite loop at node D as my output. Would love if anybody could help me out here.
#include <stdio.h>
#include <malloc.h>
struct node
{
struct node * lc;
char data;
struct node * rc;
};
char arr[] = {'A','B','C','D','E','F','G','\0','\0','H','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
struct node * root = NULL;
struct node * buildTree(int rootIndex)
{
struct node * temp = NULL;
if(arr[rootIndex]!='\0')
{
temp = (struct node *)malloc(sizeof(struct node));
temp->lc = buildTree(rootIndex * 2 + 1);
temp->data = arr[rootIndex];
temp->rc = buildTree(rootIndex * 2 + 2);
}
return temp;
}
void inorder(struct node * parent)
{
while(parent != NULL)
{
inorder(parent->lc);
printf("%c\t",parent->data);
inorder(parent->rc);
}
}
int main()
{
root = buildTree(0);
inorder(root);
return 0;
}
Like BLUEPIXY mentioned in comments, you need to replace the while in inorder() method with an if. When building tree, D forms the left-most child. Therefore during in-order traversal, D is encountered as the first node to be printed. But the while loop keeps printing it as the condition never becomes false.
I'm sure a tool like gdb would have done much better job in explaining this.
I want to know the reason why do we use, pointer to pointer while inserting nodes in the binary tree.
But, While traversing the binary tree, we just refer the tree by simple pointer to the root node. But why while inserting node?
Can anyone help me in providing the reason or reference link to understand why it is pointer to pointer .
/*This program clears out all the three methods of traversal */
#include<stdio.h>
#include<stdlib.h>
/* Let us basically describe how a particular node looks in the binary tree .... Every node in the tree has three major elements , left child, right child, and and the data. */
struct TreeNode {
int data;
struct TreeNode *leftChild;
struct TreeNode *rightChild;
};
void inorder(struct TreeNode *bt);
void preorder(struct TreeNode *bt);
void postorder(struct TreeNode *bt);
int insert(struct TreeNode **bt,int num);
main()
{
int num,elements;
struct TreeNode *bt;
int i;
printf("Enter number of elements to be inserted in the tree");
scanf("%d",&num);
printf("Enter the elements to be inserted inside the tree");
for(i=0;i<num;i++)
{
scanf("%d",&elements);
insert(&bt,elements);
printf("\n");
}
printf("In Order Traversal \n");
inorder(bt);
printf("Pre Order Traversal \n");
preorder(bt);
printf("Post Order Traversal \n");
postorder(bt);
return 0;
}
int insert(struct TreeNode **bt,int num)
{
if(*bt==NULL)
{
*bt= malloc(sizeof(struct TreeNode));
(*bt)->leftChild=NULL;
(*bt)->data=num;
(*bt)->rightChild=NULL;
return;
}
else{
/* */
if(num < (*bt)->data)
{
insert(&((*bt)->leftChild),num);
}
else
{
insert(&((*bt)->rightChild),num);
}
}
return;
}
void inorder(struct TreeNode *bt){
if(bt!=NULL){
//Process the left node
inorder(bt->leftChild);
/*print the data of the parent node */
//printf(" %d ", bt->data);
/*process the right node */
inorder(bt->rightChild);
}
}
void preorder(struct TreeNode *bt){
if(bt)
{
//Process the parent node first
printf("%d",bt->data);
//Process the left node.
preorder(bt->leftChild);
//Process the right node.
preorder(bt->rightChild);
}
}
void postorder(struct TreeNode *bt){
if(bt)
{
//process the left child
postorder(bt->leftChild);
//process the right child
postorder(bt->rightChild);
//process the parent node
printf("%d",bt->data);
}
}
"I want to know the reason why do we use, pointer to pointer while inserting nodes in the binary tree. But, While traversing the binary tree, we just refer the tree by simple pointer to the root node. But why while inserting node?"
We actually don't even need the code to answer this. If you want to modify (write to) data in an external function in C, you need to have the address of the data. Just like:
main() {
int x = 2;
change_me(x);
printf("%d\n", x); // prints 2
}
void change_me(int x){
x++;
}
has no meaning. You're (in this example) getting a local copy of the vairable, any changes made to the value are only within the local scope. If you want those changes to propagate back to the calling function you need the address:
main() {
int x = 2;
change_me(&x);
printf("%d\n", x); // prints 3
}
void change_me(int* x){
(*x)++;
}
The same applies to pointers. In the example of a linked list, if I want to print the values, I need to traverse the tree and read data. I don't need to change anything so just the pointer will do. However if I want to modify the tree:
struct node{
int val;
sturct node* next;
};
main() {
struct node* head = malloc(sizeof(struct node));
head->val = 3;
insert_a_node_in_front(head);
}
insert_a_node_in_front(node * ptr) {
struct node* temp = ptr;
ptr = malloc(sizeof(struct node));
ptr->val = 5;
ptr->next = temp;
}
Well, guess what? We didn't actually just insert that node because head's value never changed. It's still pointing to the original node with a val==3. The reason is the same as before, we tried to change the value of the local copy of the parameter. If we want those changes to stick it needs the address of the original copy:
insert_a_node_in_front(&head);
}
insert_a_node_in_front(node ** ptr) {
struct node* temp = (*ptr);
(*ptr) = malloc(sizeof(struct node));
(*ptr)->val = 5;
(*ptr)->next = temp;
}
It's because of the first part of insert where it mallocs a new struct treenode. If you only passed in a struct treenode * this would look something like this:
int insert(struct TreeNode *bt,int num)
{
if(bt==NULL)
{
bt= malloc(sizeof(struct TreeNode));
(bt)->leftChild=NULL;
(bt)->data=num;
(bt)->rightChild=NULL;
return;
}
...
}
The problem with that would be that bt is local to insert so the bt in main would be unchanged. So you pass in a pointer to main's bt, which allows insert to change it.
a very good tips on using pointer is given here :
Try this basics : -
http://www.geeksforgeeks.org/how-to-write-functions-that-modify-the-head-pointer-of-a-linked-list/