Removing items from a tree structure - c

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

Related

C - Binary Search Tree, delete node

I have a question about my Code. "delete_single_node" does not work as it should. My procedure (to delete a node) is to find the node in the "head" tree, save the child nodes temporary, delete the node and all child nodes (in "head" tree) and merge the "head" tree with the temporary saved child nodes to a new correct binary tree.
I would like to stay with this procedure but I can't find my mistake.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
struct tnode {
int content;
struct tnode *left;
struct tnode *right;
};
struct tnode* head;
void *malloc(size_t size);
struct tnode *talloc(void)
{
return(struct tnode*)malloc(sizeof(struct tnode));
}
/* delete a node with all child nodes*/
int deletenode(struct tnode *p)
{
if (p == NULL) return 0;
else
{
deletenode(p->left);
deletenode(p->right);
p->left = NULL;
p->right = NULL;
free(p);
return 0;
}
}
/* insert new node*/
struct tnode *addelement(struct tnode *p, int i) {
int cond;
if (p == NULL) {
p = talloc();
p->content = i;
p->left = p->right = NULL;
}
else if (p->content == i) {
return p;
}
else if (i < p->content)
p->left = addelement(p->left, i);
else
p->right = addelement(p->right, i);
return p;
}
/*merges two binary trees into one*/
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);
}
/*prints out tree*/
void showtree(struct tnode* nd)
{
if (nd == NULL)
return;
printf("ZZ %d", nd->content);
if (nd->left != NULL)
{
printf("left:%d", nd->left->content);
}
if (nd->right != NULL)
{
printf("right:%d\n", nd->right->content);
}
printf("\n");
showtree(nd->left);
showtree(nd->right);
}
/*removes connection to a node*/
void removeconnection(struct tnode *head, struct tnode *p) {
if (p->content > head->content) {
if (head->right == p)
{
head->right = NULL;
}
else
{
removeconnection(head->right, p);
}
}
if (p->content < head->content) {
if (head->left == p)
{
head->left = NULL;
}
else
{
removeconnection(head->left, p);
}
}
}
/*delete single node*/
struct tnode *delete_single_node(struct tnode *p, int content) {
struct tnode* temp2 = NULL;
struct tnode temp1;
struct tnode* temp4 = NULL;
struct tnode temp3;
if (p == NULL)
return NULL;
if (content > p->content)
{
p->right = delete_single_node(p->right, content);
}
else if (content < p->content)
{
p->left = delete_single_node(p->left, content);
}
else if (content == p->content)
{
if (p->left == NULL && p->right != NULL)
{
temp1.content = p->right->content;
temp1.right = p->right->right;
temp1.left = p->right->left;
temp2 = &temp1;
removeconnection(head, p);
deletenode(p);
head = addtree(head, temp2);
showtree(head);
}
else if (p->right == NULL && p->left != NULL)
{
temp1.content = p->left->content;
temp1.right = p->left->right;
temp1.left = p->left->left;
temp2 = &temp1;
removeconnection(head, p);
deletenode(p);
head = addtree(head, temp2);
showtree(head);
}
else if (p->right == NULL && p->left == NULL)
{
removeconnection(head, p);
deletenode(p);
showtree(head);
}
else
{
temp1.content = p->left->content;
temp1.right = p->left->right;
temp1.left = p->left->left;
temp2 = &temp1;
temp3.content = p->right->content;
temp3.right = p->right->right;
temp3.left = p->right->left;
temp4 = &temp3;
removeconnection(head, p);
deletenode(p);
head = addtree(head, temp2);
head = addtree(head, temp4);
showtree(head);
}
}
}
int main()
{
struct tnode* start = NULL;
int temp_int;
start = addelement(start, 5);
start = addelement(start, 6);
start = addelement(start, 2);
start = addelement(start, 9);
start = addelement(start, 3);
start = addelement(start, 2);
start = addelement(start, 1);
start = addelement(start, 7);
start = addelement(start, 8);
showtree(start);
printf("Which node to delete?\n");
scanf_s("%d", &temp_int);
head = start;
delete_single_node(start, temp_int);
return 0;
}

Pointer in function to linked list not updating element in 1 case

I am using a struct like this
struct infoM {
char* direction;
int key;
};
typedef struct nodeM{
struct infoM nodeInfo;
struct nodeM *next;
struct nodeM *prev;
} node;
typedef node list;
I have one function that returns the wanted node by a specific field
node * search(list *l, char* direction) {}
And this is my function to remove elements from the list
int delete(list *l, char* direction) {
node *tmp = search(l, direction);
if (tmp != NULL) {
node *ant = tmp->prev;
node *seg = tmp->next;
if (seg != NULL) {
if (ant != NULL) {
ant->next = seg;
seg->prev = ant;
free(tmp);
return 1;
} else { //prev null
seg->prev = NULL;
*l = *seg;
tmp = NULL;
free(tmp);
return 1;
}
} else { //next null
if (ant == NULL) {
l->nodeInfo.key = somevalue;
l->next = NULL;
l->prev = NULL;
return 1;
} else {
printf("Here is the problem\n");
ant->next = NULL;
free(tmp);
return 1;
}
}
} else { //tmp nulo
perror("Error delete : node null\n");
return 0;
}
}
If I have 4 elements in the list, 1234 and I delete first first element everything is okay and returns 234. If I delete the last element it returns 23 seems to work great. But if I try to delete the last element now the function does nothing despite being the same case that when it is 234 and I don't understand why. The list is not being updated.
In the main I am using the list like this :
list a;
delete(&a, "whatever");
What am I doing wrong ?
This is the code for search
node * createnode(){
node *tmp = (node *) malloc (sizeof(node));
return tmp;
}
node * search(list *l, char* direction) {
node *tmp = createnode();
if (l->nodeInfo.key == 777) {
perror("Error search: empty list\n");
return NULL;
}
tmp=l;
while((strcmp(direction, tmp->nodeInfo.direction) !=0) && (tmp->next != NULL)) {
tmp = tmp->next;
}
if (strcmp(direction, tmp->nodeInfo.direction) == 0) {
return tmp;
} else {
perror("Error search: element not found\n");
return NULL;
}
}

Binary Search tree, node deletion crash

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?

printing a pointer value

i have this issue while trying to print *p value while p is pointed to a nodo of the list (obviusly i would like to print the nodo.info value)
here is the code, hope u understand:
struct nodo {
int info;
struct nodo *prec;
struct nodo *succ;
} ;
typedef struct nodo nodo;
int main (void) { // just declaring my 3 nodos
struct nodo *p;
struct nodo anodo;
struct nodo bnodo;
struct nodo cnodo;
anodo.info = 200;
anodo.prec = NULL;
anodo.succ = NULL;
bnodo.info = 22;
bnodo.prec = NULL;
bnodo.succ = NULL;
cnodo.info = 2000;
cnodo.prec = NULL;
cnodo.succ = NULL;
anodo.succ = &bnodo;
bnodo.prec = &anodo;
bnodo.succ = &cnodo;
cnodo.prec = &bnodo;
p = &anodo;
printf("\n%d\n", checklist (p)); // calling function
return 0;
}
nodo *checklist (struct nodo *p) {
int j=0;
while (p != NULL) {
if (p->info >= p->succ->info) { //if first element is major or same than next
p=p->succ;
} else {
while (p != NULL) {
if (p->info >= p->succ->info) { //same
p=p->succ;
j++;
} else {
p = NULL;
}
}
}
}
while (j != 0) {
p = p->prec; //used a counter to get back to the first nodo in wich next was less than prev
j--;
}
return p;
}
feel free to ask any details
p = checklist (p);
if (p)
printf("\n%d\n", p->info);
You need to return the nodo.info then
int checklist (struct nodo *p) {
int j=0;
while (p != NULL) {
/* avoid this p->succ->info */
if (p->info >= p->succ->info) { //if first element is major or same than next
p = p->succ;
} else {
while (p != NULL) {
if (p->info >= p->succ->info) { //same
p = p->succ;
j++;
} else {
p = NULL;
}
}
}
}
while (j != 0) { p = p->prec; //used a counter to get back to the first nodo in wich next was less than prev
j--;
}
return p->info;
}
or in main
int info
struct nodo *found;
found = checklist(p);
if (found != NULL)
printf("\n%d\n", found->info);

adding nodes to a binary search tree randomly deletes nodes

stack. I've got a binary tree of type TYPE (TYPE is a typedef of data*) that can add and remove elements. However for some reason certain values added will overwrite previous elements. Here's my code with examples of it inserting without overwriting elements and it not overwriting elements.
the data I'm storing:
struct data {
int number;
char *name;
};
typedef struct data data;
# ifndef TYPE
# define TYPE data*
# define TYPE_SIZE sizeof(data*)
# endif
The tree struct:
struct Node {
TYPE val;
struct Node *left;
struct Node *rght;
};
struct BSTree {
struct Node *root;
int cnt;
};
The comparator for the data.
int compare(TYPE left, TYPE right) {
int left_len; int right_len; int shortest_string;
/* find longest string */
left_len = strlen(left->name);
right_len = strlen(right->name);
if(right_len < left_len) { shortest_string = right_len; } else { shortest_string = left_len; }
/* compare strings */
if(strncmp(left->name, right->name, shortest_string) > 1) {
return 1;
}
else if(strncmp(left->name, right->name, shortest_string) < 1) {
return -1;
}
else {
/* strings are equal */
if(left->number > right->number) {
return 1;
}
else if(left->number < right->number) {
return -1;
}
else {
return 0;
}
}
}
And the add method
struct Node* _addNode(struct Node* cur, TYPE val) {
if(cur == NULL) {
/* no root has been made */
cur = _createNode(val);
return cur;
}
else {
int cmp;
cmp = compare(cur->val, val);
if(cmp == -1) {
/* go left */
if(cur->left == NULL) {
printf("adding on left node val %d\n", cur->val->number);
cur->left = _createNode(val);
}
else {
return _addNode(cur->left, val);
}
}
else if(cmp >= 0) {
/* go right */
if(cur->rght == NULL) {
printf("adding on right node val %d\n", cur->val->number);
cur->rght = _createNode(val);
}
else {
return _addNode(cur->rght, val);
}
}
return cur;
}
}
void addBSTree(struct BSTree *tree, TYPE val)
{
tree->root = _addNode(tree->root, val);
tree->cnt++;
}
The method to create a new node:
struct Node* _createNode(TYPE val) {
struct Node* new_node;
new_node = (struct Node*)malloc(sizeof(struct Node*));
new_node->val = val;
new_node->left = NULL;
new_node->rght = NULL;
return new_node;
}
The function to print the tree:
void printTree(struct Node *cur) {
if (cur == 0) {
printf("\n");
}
else {
printf("(");
printTree(cur->left);
printf(" %s, %d ", cur->val->name, cur->val->number);
printTree(cur->rght);
printf(")\n");
}
}
Here's an example of some data that will overwrite previous elements:
struct BSTree myTree;
struct data myData1, myData2, myData3;
myData1.number = 5;
myData1.name = "rooty";
myData2.number = 1;
myData2.name = "lefty";
myData3.number = 10;
myData3.name = "righty";
initBSTree(&myTree);
addBSTree(&myTree, &myData1);
addBSTree(&myTree, &myData2);
addBSTree(&myTree, &myData3);
printTree(myTree.root);
Which will print:
((
righty, 10
)
lefty, 1
)
Finally here's some test data that will go in the exact same spot as the previous data, but this time no data is overwritten:
struct BSTree myTree;
struct data myData1, myData2, myData3;
myData1.number = 5;
myData1.name = "i";
myData2.number = 5;
myData2.name = "h";
myData3.number = 5;
myData3.name = "j";
initBSTree(&myTree);
addBSTree(&myTree, &myData1);
addBSTree(&myTree, &myData2);
addBSTree(&myTree, &myData3);
printTree(myTree.root);
Which prints:
((
j, 5
)
i, 5 (
h, 5
)
)
Does anyone know what might be going wrong? Sorry if this post was kind of long.
it looks like there is an error in your _addNode procedure. It looks like you arent properly storing the new node references in the tree.
struct Node* _addNode(struct Node* cur, TYPE val) {
if(cur == NULL) {
/* no root has been made */
cur = _createNode(val);
return cur;
}
else {
int cmp;
cmp = compare(cur->val, val);
if(cmp == -1) {
/* go left */
cur->left = _addNode(cur->left, val);
}
else if(cmp >= 0) {
/* go right */
cur->left = _addNode(cur->right, val);
}
return cur;
}
the _addnode function was kind of confusing because you were using the return value inconsistently. i believe this version should avoid loosing any nodes.
I don't see an obvious flaw. I would suggest reworking the tree to hold int's or something simpler than your current data. If the tree works fine then at least you know where to look and not worry about the generic tree code.
I suspect _createNode(), can you add that code?

Resources