so i coded a binary search tree in C which looks with this struct:
struct tnode {
int content;
struct tnode *left; /* left tree part */
struct tnode *right; /* right tree part */
};
My main method:
int main() {
struct tnode *Baum = NULL;
struct tnode *tmpPos = NULL;
Baum = addelement (Baum, 32);
Baum = addelement(Baum, 50);
Baum = addelement(Baum, 60);
tmpPos = searchnode(Baum,50);
}
So basicly this creates me a Binary search tree with 3 elements (32,50,60). My searchnode method is supposed to move a pointer to the "50" so i can delete it afterwards. However my searchnode Method only returns the pointer if the element im searching is the root of my binary search tree.
searchnode:
struct tnode *searchnode(struct tnode *p, int nodtodelete) {
if (p == NULL) {
printf("Baum ist leer oder Element nicht vorhanden \n");
}
if ( p -> content == nodtodelete) {
return p;
}
if (p->content > nodtodelete) {
searchnode (p->right, p->content);
}
if (p->content < nodtodelete) {
searchnode(p->left, p->content);
}
}
Maybe you guys can help me.
Your function has undefined behavior since it doesn't have any return statements in the recursive calls.
Also, the recursive calls need to be fixed to use the right input.
struct tnode *searchnode(struct tnode *p, int nodtodelete)
{
if (p == NULL)
{
printf("Baum ist leer oder Element nicht vorhanden \n");
return NULL;
}
if ( p -> content == nodtodelete)
{
return p;
}
// This is copied from OP's question but it seems suspect.
// It should probably be:
// if (p->content < nodtodelete)
if (p->content > nodtodelete)
{
return searchnode (p->right, nodtodelete);
}
return searchnode(p->left, nodtodelete);
}
You should pass the value you're searching for, not the value of the node:
searchnode (p->right, nodtodelete);
^
Make the same change to the other recursive call.
searchnode(p->left, nodtodelete);
Related
I have this struct:
typedef struct Tree {
int arrel;
struct Tree *dret;
struct Tree *esq;
unsigned int talla;
} Tree;
With the following methods:
void crearArbre (struct Tree *arbre, int val_arrel)
{
arbre->arrel = val_arrel;
arbre->dret = NULL;
arbre->esq = NULL;
arbre->talla = 0;
}
int inserir (struct Tree *arbre, int valor) //Insert method
{
struct Tree *aux = arbre;
struct Tree *ant = NULL;
while (aux != NULL && aux->arrel - valor != 0)
{
ant = aux;
if (aux->arrel > valor)
{
aux = aux->esq;
}
else
aux = aux->dret;
}
if (aux == NULL)
{
if (ant->arrel > valor)
{
//ant -> esq -> arrel = valor;
ant->esq = (struct Tree *) malloc (sizeof (struct Tree));
ant->esq->arrel = valor;
//crearArbre(ant -> esq ,valor);
}
else
{
ant->dret = (struct Tree *) malloc (sizeof (struct Tree));
ant->dret->arrel = valor;
}
}
arbre->talla += 1;
return 0;
}
int rem (struct Tree *arbre, int valor) //Remove method
{
if (arbre == NULL)
return NULL;
if (valor < arbre->arrel)
{
return rem (arbre->esq, valor);
}
else if (valor > arbre->arrel)
{
return rem (arbre->dret, valor);
}
else
{
int val = arbre->arrel;
arbre = NULL; //Not sure about this
free (arbre); //?
return val;
}
}
void printarArbre (struct Tree *arbre) //Post order printing method
{
if (arbre != NULL)
{
printarArbre (arbre->esq);
printarArbre (arbre->dret);
printf ("%d -> ", arbre->arrel);
}
}
I have been testing the struct by inserting some numbers, find them and finally remove some elements. But, after I remove an element from the tree and calling free(), if I call printarArbre(), in the position that was the element previously removed, if I set (arbre = NULL) and then free(arbre), why is it still being printed? Do I need a flag to indicate whether a node has been removed?
Please see also the comments. The proper way would be:
int rem (struct Tree **arbreIn, int valor) //Remove method
{
struct Tree *arbre= *arbreIn; // shorthand
if (arbre == NULL)
return NULL;
if (valor < arbre->arrel)
{
return rem (&(arbre->esq), valor);
}
else if (valor > arbre->arrel)
{
return rem (&(arbre->dret), valor);
}
else
{
int val = arbre->arrel;
free (arbre); // free the node
*arbreIn = NULL; // set the parent's pointer (esq or dret) to null
return val;
}
}
I am making a simple BST and, in the add_to_bst() function, it is throwing an error in the first line when referencing the object's value.
CODE
typedef struct node {
int value;
struct node* leftChild;
struct node* rightChild;
} BSTNode;
BSTNode *new_BSTNode(int val) {
BSTNode *this = (BSTNode *) malloc(sizeof(BSTNode));
this->value = val;
this->leftChild = (BSTNode * ) malloc(sizeof(BSTNode));
this->rightChild = (BSTNode * ) malloc(sizeof(BSTNode));
this->leftChild = NULL;
this->rightChild = NULL;
return this;
}
typedef struct bst {
BSTNode * root;
} BST;
BST *new_BST(int root_val) {
BST *this = (BST *) malloc(sizeof(BST));
this->root = (BST * ) malloc(sizeof(BSTNode));
this->root->value = root_val;
// this->root->value = (int *) malloc(sizeof(int));
return this;
}
int node_get(BSTNode *n, int i) {
if (n == NULL) return -1;
if (i == n-> value) return 1;
if (i > n-> value) return node_get(n->rightChild, i);
else return node_get(n->leftChild, i);
}
int bst_get(BST *bst, int i) {
return node_get(bst->root, i);
}
void add_to_bst_node(int i, BSTNode *to) {
int n = to->value; // <--- ERR
printf("\nBST VAL: %d", n);
if (i > n) {
if (to->rightChild == NULL)
to->rightChild = new_BSTNode(i);
else
add_to_bst_node(i, to->rightChild);
} else {
if (to->leftChild == NULL)
to->leftChild = new_BSTNode(i);
else
add_to_bst_node(i, to->leftChild);
}
}
void add_to_bst(BST *tree, int i) {
if (tree->root != NULL) {
add_to_bst_node(i, tree->root);
} else {
tree->root = new_BSTNode(i);
}
}
int main() {
BST *bst = new_BST(10);
add_to_bst(bst, 10);
}
RUN MSG:
0x7fa64fc00690
0x7fa64fc00640
First Val: 10
Process finished with exit code 11
BUILD ERR:
BSTNode *new_BSTNode(int val) {
BSTNode *this = (BSTNode *) malloc(sizeof(BSTNode));
this -> value = val;
this -> leftChild = (BSTNode * ) malloc(sizeof(BSTNode));
this -> leftChild = (BSTNode * ) malloc(sizeof(BSTNode));
return this;
}
This leaves this->rightChild uninitialized and leaves this->leftChild pointing to uninitialized garbage. Neither of these issues is fixed in the code that calls new_BSTnode.
void add_to_bst_node(int i, BSTNode *to) {
int n = to -> value; // <------ ERROR
Not surprising, since to comes from leftChild and rightChild, both of which are broken by the logic of new_BSTNode.
Also:
BST *new_BST(int root_val) {
BST *this = (BST *) malloc(sizeof(BST));
this -> root = (BST * ) malloc(sizeof(BSTNode));
this -> root -> value = root_val;
// this -> root -> value = (int *) malloc(sizeof(int));
return this;
}
This doesn't set this->root->leftChild or this->root->rightChild either, so again, they're garbage that gets passed to add_to_bst_node as to.
The creation of the new node, and insertion into the tree seems incorrect.
A new node should not allocate space for the left and right subtrees. Since new nodes are always added to the extremities, they never have subtrees when new anyway.
BSTNode *new_BSTNode( int val )
{
BSTNode *this = ( BSTNode * ) malloc( sizeof( BSTNode ) );
if ( this != NULL )
{
this->value = val;
this->leftChild = NULL;
this->rightChild = NULL;
}
return this;
}
Using a recursive algorithm when inserting new data allows the code to "walk" the tree, finding the correct place for insertion.
void add_to_bst_node( int value, BSTNode *to )
{
if (to != NULL)
{
if (value > to->value)
{
// Add to child-right subtree
if (to->rightChild == NULL)
{
// right-tree is empty, create it
to->rightChild = new_BSTNode( value );
}
else
{
// add it somewhere on the right-side (recursively)
add_to_bst_node( value, to->rightChild );
}
}
else // if (i <= to->value)
{
// Add to child-left subtree
if (to->leftChild == NULL)
{
// left-tree is empty, create it
to->leftChild = new_BSTNode( value );
}
else
{
// add it somewhere on the right-side (recursively)
add_to_bst_node( value, to->leftChild );
}
}
}
}
A tree is just a node. Making a separate structure for a "tree" is just extra work.
typedef BSTNode BST;
So the creation of a tree, is just the creation of a node:
BST *new_BST( int value )
{
return new_BSTNode( value );
}
The branch in add_to_BST() always chooses the tree->root != NULL if it was initialised error-free. Then the add_to_BST_node() dereferences garbage, (as the other answers have pointed out); here is a graphical representation of the memory allocating functions,
And,
I recommend thinking about what the states are in ones system and drawing them out first so one doesn't fall into an invalid state. Also, if one is doing a constructor, it's a good idea to initialise the entire structure.
this is a binary tree queue problem
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define NUM 10
typedef struct _node
{
int value;
struct _node *left;
struct _node *right;
}TNode,*Tree;
add a *next in q_node is my purpose
other wise , we need to add in the Tree node struct
So, for the sake of doesn't modify the struct of tree
I design a q_node struct to include it
we can use define command to make it as a template.
typedef struct _q_node
{
TNode *t_node;
int length;
struct _q_node *next;
}QNode;
typedef struct _Queue
{
QNode *head;
QNode *tail;
}Queue;
Queue* init_queue()
{
Queue *queue=(Queue*)malloc(sizeof(Queue));
queue->head = queue->tail = NULL;
return queue;
}
int enQueue(Queue *pQueue,TNode *pTNode)
{
QNode *pQNode = (QNode *)malloc(sizeof(QNode));
pQNode->t_node = pTNode;
if(pQueue->head == NULL)
{//when it's empty
pQueue->head = pQNode;
pQueue->tail = pQNode;
}
else
{
pQueue->tail->next = pQNode;
pQueue->tail = pQNode;
}
}
QNode* deQueue(Queue *pQueue)
{
if(pQueue->head == NULL)
{
return NULL;
}
QNode *deNode= pQueue->head;
pQueue->head = pQueue->head->next;
return deNode;
}
TNode* init_TNode(int value)
{
TNode *new_node = (TNode*)malloc(sizeof(TNode));
new_node->value=value;
new_node->left = new_node->right = NULL;
return new_node;
}
//0:empty
int ifEmpty(Queue *pQueue)
{
if(pQueue->head == NULL)
{
//printf("empty tree\n");
return 0;
}
//printf("queue is not empty\n");
return 1;
}
int insert_tree(Tree pTree,int pValue)
{
//found NULL sub tree, then add to his father->left
if(!pTree)
{
return 0;
}
TNode *tNode = init_TNode(pValue);
if(tNode==NULL)
{
printf("create TNode error!\n");
return 0;
}
if(pValue < pTree->value)
if(insert_tree(pTree->left,pValue)==0)
{
//no left child any more,set a new left child to pTree
pTree->left = tNode;
printf("insert :%d\n",pValue);
}
if(pValue > pTree->value)
if(insert_tree(pTree->right,pValue)==0)
{
pTree->right = tNode;
printf("insert :%d\n",pValue);
}
}
Tree creatTree()
{
srand(time(NULL));
Tree root = init_TNode(rand()%100);
printf("root is %d\n",root->value);
int i ;
for(i=1;i<NUM;i++)
{
insert_tree(root,rand()%100);
}
printf("creat tree succuess!Tree heigh is:%d\n",get_tree_height(root));
return root ;
}
int get_tree_height(Tree pRoot)
{
if(!pRoot)
{
return 0;
}
int lh=0,rh=0;
lh = get_tree_height(pRoot->left);
rh = get_tree_height(pRoot->right);
return (lh<rh)?(rh+1):(lh+1);
}
int breath_travel(Tree pRoot,Queue *pQueue)
{
if(!pRoot)
{
return 0;
}
enQueue(pQueue,pRoot);
printf("_______________________\n");
printf("breath begin,enter root:\n");
while(ifEmpty(pQueue)!=0)
{
QNode *qNode = deQueue(pQueue);
//make suer every enQueue Node is not NULL
if(qNode->t_node->left!=NULL)
{enQueue(pQueue,qNode->t_node->left);}
if(qNode->t_node->right!=NULL)
{
enQueue(pQueue,qNode->t_node->right);
}
//print the tree node value
printf("%d ",qNode->t_node->value);
}
printf("\n-----------\nbreath end!\n-----------\n");
return 1;
}
int main()
{
Queue *queue=init_queue();
int i;
ifEmpty(queue);
printf("insert node to queue\n");
Tree root = creatTree();
if(!root)
{
printf("create Tree failed!\n");
return 0;
}
breath_travel(root,queue);
// free(queue);
return 0;
}
if this version can function well in my computer i have to add a unused int
"int length" in the beginning " _q_node" structure , if i don't add it the ifEmpty function cannot find the right position like "pQueue->head == NULL"
why this happen?
Your program has a bug in the insert_tree function. I have added a few comments to your code:
int insert_tree(Tree pTree,int pValue)
{
//found NULL sub tree, then add to his father->left
if(!pTree)
{
return 0;
}
TNode *tNode = init_TNode(pValue);
if(tNode==NULL)
{
printf("create TNode error!\n");
return 0;
}
if(pValue < pTree->value)
if(insert_tree(pTree->left,pValue)==0) // Here the return value is used
{
//no left child any more,set a new left child to pTree
pTree->left = tNode;
printf("insert :%d\n",pValue);
}
if(pValue > pTree->value)
if(insert_tree(pTree->right,pValue)==0) // Here the return value is used
{
pTree->right = tNode;
printf("insert :%d\n",pValue);
}
// No return value here !!
}
As you can see from my comments you miss a return value at the end of the function. Since you use that return value in other places, you program uses some uninitialized return value. That can make your program fail.
BTW: enQueue miss a return value as well.
An advice: Always compile your code with a high warning level and consider all warnings to be errors. In other words - if there are warnings they shall be fixed before running the code.
If you compile using gcc use -Wall to get all warnings
Besides that I think there is a problem with the logic in this function. It uses recursion to find where to insert the new value. In each recursive call you create a new node using TNode *tNode = init_TNode(pValue); but you only use it at the end of the recursion. In other words it seems you have memory leaks.
Further it's unclear how/where you handle the case where pValue is equal to pTree->value
BTW: pValue is a real bad name for an integer as the p makes you think it's a pointer.
I coded a Binary Search tree. Every function works just fine, but the "deletenode". This method is supposed to delete the node which *p is pointing at.
However if the node is a leaf it prints the tree without the node and crashes.
If the node is no leaf it doesnt even print the tree and crashes.
I dont see any possible way to recreate the problem in less code, because i dont know where the problem is supposed to be. I'm Sorry.
Maybe someone can load it up and see where the problem is, because im really desperate.
#include <stdio.h>
void *malloc(size_t size);
void free(void *ptr);
struct tnode {
int content;
struct tnode *left; /* left subtree */
struct tnode *right; /* right subtree */
};
struct tnode *talloc(void) /* reserves memory*/
{
return (struct tnode *) malloc(sizeof(struct tnode));
}
struct tnode *addelement(struct tnode *p, int i) /* addelement: adds new node */
{
int cond;
if(p == NULL) {
p = talloc(); /* make a new node */ p->content = i;
p->left = p->right = NULL;
} else if(p->content == i) {
return p;
} else if(i < p->content) /* goes to the left side */ p->left = addelement(p->left, i);
else /* goes to the right side */ p->right = addelement(p->right, i);
return p;
}
struct tnode *addtree(struct tnode *top, struct tnode *p) /* adds subtree to main tree*/
{
if(p == NULL)
return top;
else
return addtree(addtree(addelement(top, p->content), p->right), p->left);
}
int printtree_preorder(struct tnode *p) /* prints tree in preorder*/
{
if(p != NULL) {
printf("%d \n", p->content);
printtree_preorder(p->left);
printtree_preorder(p->right);
}
return 0;
}
int printtree_inorder(struct tnode *p) /* prints tree in inorder*/
{
if(p != NULL) {
printtree_inorder(p->left);
printf("%d \n", p->content);
printtree_inorder(p->right);
}
return 0;
}
int printtree_postorder(struct tnode *p) /* prints tree in postorder*/
{
if(p != NULL) {
printtree_postorder(p->left);
printtree_postorder(p->right);
printf("%d \n", p->content);
}
return 0;
}
struct tnode *searchnode(struct tnode *p, int nodtodelete) /* pointer is set on the node which is supposed to be deleted */
{
if(p == NULL) {
printf("Baum ist leer oder Element nicht vorhanden \n");
return 0;
}
if(p->content == nodtodelete) {
return p;
}
if(p->content < nodtodelete) {
return searchnode(p->right, nodtodelete);
}
if(p->content > nodtodelete) {
return searchnode(p->left, nodtodelete);
}
}
struct tnode *deletenode(struct tnode *p, struct tnode *pBaum) /* Is supposed to delete the node which the *p is pointing at */
{
if((p->left == NULL) && (p->right == NULL)) {
free(p);
printf("Ist Blatt \n");
return pBaum;
}
if((p->left == NULL) && (p->right != NULL)) {
struct tnode *rechterTeilbaum = p->right;
free(p);
pBaum = addtree(pBaum, rechterTeilbaum);
return pBaum;
}
if((p->right == NULL) && (p->left != NULL)) {
struct tnode *linkerTeilbaum = p->left;
free(p);
pBaum = addtree(pBaum, linkerTeilbaum);
return pBaum;
}
if((p->left != NULL) && (p->right != NULL)) {
struct tnode *rechterTeilbaum = p->right;
struct tnode *linkerTeilbaum = p->left;
free(p);
pBaum = addtree(pBaum, rechterTeilbaum);
pBaum = addtree(pBaum, linkerTeilbaum);
return pBaum;
}
}
int main() {
struct tnode *Baum = NULL;
struct tnode *tmpPos = NULL;
Baum = addelement(Baum, 10);
Baum = addelement(Baum, 30);
Baum = addelement(Baum, 20);
Baum = addelement(Baum, 35);
tmpPos = searchnode(Baum, 35);
if(tmpPos != 0) {
printf("Zu loeschendes Element: %d \n", tmpPos->content);
Baum = deletenode(tmpPos, Baum);
}
printf("Inorder Ausgabe\n");
printtree_inorder(Baum);
printf("Postorder Ausgabe\n");
printtree_postorder(Baum);
printf("Preorder Ausgabe\n");
printtree_preorder(Baum);
}
In the deletenode function, you aren't checking to see if p is NULL before you try to dereference it. Are you segfaulting?
I've created my binary search tree and gave the pointer to the node which I want to delete into my *p.
The delete method is supposed to be deleting the node which is pointed at by *p and should add the subtrees with addtree to my root. *pBaum is the pointer which points to my root.
However im getting an error message called "conflict types" on addtree everytime I declare
Baum = addtree(Baum, p->right);
I also get a warning "assignment makes pointer from integer without a cast"
My struct contains left & right pointer to the subtrees and a pointer to the content.
struct tnode
{
int content;
struct tnode *left; /* linker Teilbaum */
struct tnode *right; /* rechter Teilbaum */
};
// Deletes the node where *p is pointing at
struct tnode *deletenode(struct tnode *p, struct tnode *pBaum)
{
struct tnode *Baum = pBaum;
if ((p->left == NULL) && (p->right == NULL))
{
free(p);
}
if ((p->left == NULL) && (p->right != NULL))
{
Baum = addtree(Baum, p->right);
free(p);
}
if ((p->right == NULL) && (p->left !=NULL))
{
Baum = addtree(Baum, p->left);
free(p);
}
if ((p->left != NULL) && (p->right !=NULL))
{
Baum = addtree(Baum, p->right);
Baum = addtree(Baum, p->left);
free(p);
}
return Baum;
}
// Adds the Subtrees to my root
struct tnode *addtree(struct tnode *top, struct tnode *p)
{
if (p == NULL)
return top;
else
return addtree(addtree(addelement(top, p->content),p-> right), p->left);
// Adds a node to my Tree
struct tnode *addelement(struct tnode *p, int i)
{
int cond;
if (p == NULL)
{
p = talloc(); /* make a new node */ p->content = i;
p->left =p->right =NULL;
}
else if (p->content == i)
{
return p;
}
else if (i < p->content) /* goes into left subtree */ p->left =addelement(p->left, i);
else /* goes into right subtree */ p->right = addelement(p->right, i);
return p;
}
// Looks for the node which is supposed to get deleted and returns a pointer to it
struct tnode *searchnode(struct tnode *p, int nodtodelete)
{
if (p == NULL)
{
printf("Baum ist leer oder Element nicht vorhanden \n");
return NULL;
}
if ( p -> content == nodtodelete)
{
return p;
}
if (p->content < nodtodelete)
{
return searchnode (p->right, nodtodelete);
}
if (p->content > nodtodelete)
{
return searchnode(p->left, nodtodelete);
}
}
}
int main()
{
struct tnode *Baum = NULL;
struct tnode *tmpPos = NULL;
Baum = addelement (Baum, 32);
Baum = addelement(Baum, 50);
Baum = addelement(Baum, 60);
tmpPos = searchnode(Baum,50);
Baum = deletenode(tmpPos, Baum);
}
Have you declare the function before function call in code ? i declare the addtree and addelement functions on top of the file and error for conflict types is gone.
I'm not sure if this is due to you only including partial code, but you addtree function is not complete:
struct tnode *addtree(struct tnode *top, struct tnode *p)
{
if (p == NULL)
return top;
else
return addtree(addtree(addelement(top, p->content),p-> right), p->left);
This function needs to be ended with a bracket:
struct tnode *addtree(struct tnode *top, struct tnode *p)
{
if(p == NULL)
return top;
return addtree(addtree(addelement(top, p->content), p->right), p->left);
}
To make it so the compiler doesn't potentially complain about not returning a value in a non void function it's best to get rid of the else as well.