I would like to know if it is possible to free an entire binary search tree in preorder mode. I've got this function:
void preorder_del(struct s_nodo ** tree)
{
if (*tree != NULL)
{
free(*tree);
preorder_del(&(*tree)->left);
preorder_del(&(*tree)->right);
}
}
I don't think this works, freeing the first leaf of the tree wont let me recall preorder, right?
You should record left and right locally to avoid accessing freed pointer after free(*tree).
if (*tree != NULL)
{
struct s_nodo *l = (*tree)->left;
struct s_nodo *r = (*tree)->right;
free(*tree);
preorder_del(&l);
preorder_del(&r);
}
Related
I have a question about these two algorithms:
This works normally:
node* deleteTree(node* root)
{
if(root != NULL)
{
deleteTree(root->left);
deleteTree(root->right);
deallocateNode(root);
}
return root=NULL;
}
This nope:
void deleteTree(node* root)
{
if(root != NULL)
{
deleteTree(root->left);
deleteTree(root->right);
deallocateNode(root);
}
root=NULL;
}
Why? I need to set the root to null so the node pointer after the delete of the BST will not point to a memory not allocated.
I prefer the second algorithm because the recall of the function is more intuitive.
Theoretically, the two algorithms are equivalent but if I use the second algorithm and I try to print the BST, the program goes in a loop.
When you have node *root and assign node = NULL it won't affect its value in exterior. If you want to modify the pointer value, you'll have to pass a double pointer.
Something like:
void deleteTree(node** root)
{
if(*root != NULL)
{
deleteTree(&((*root)->left));
deleteTree(&((*root)->right));
deallocateNode(*root);
}
*root = NULL;
}
But I don't really think you need to assign node = NULL since you free it. So, you can just assign node = NULL after you call deleteTree and you won't need to mess with double pointer.
I am working on a C binary search tree library and I'm trying to write a function that will delete the left node of the tree subtree. Here's the struct of my tree:
struct Node {
int value;
struct Node *left;
struct Node *right;
};
typedef struct Node TNode;
typedef struct Node *binary_tree;
The tree is created like this:
binary_tree NewBinaryTree(int value_root) {
binary_tree newRoot = malloc(sizeof(TNode));
if (newRoot) {
newRoot->value = value_root;
newRoot->left = NULL;
newRoot->right = NULL;
}
return newRoot;
}
Adding element to it:
void Insert(binary_tree *tree, int val) {
if (*tree == NULL) {
*tree = (binary_tree)malloc(sizeof(TNode));
(*tree)->value = val;
(*tree)->left = NULL;
(*tree)->right = NULL;
} else {
if (val < (*tree)->value) {
Insert(&(*tree)->left, val);
} else {
Insert(&(*tree)->right, val);
}
}
}
The delleftsubtreenode I did:
void delleftsubtree(binary_tree *tree){
if( (*tree)->value!=NULL )
{
free(&(*tree)->left);
delleftsubtree( &(*tree)->left);
}
else
{
printf("end");
}
}
This method compile,however when I try to call it the program just crash.I dont understand why or how else to do that function.
thank you!
As Olaf said in his comment, you have several problems; calling "free()" with a pointer then attempting to dereference it, and use of double indirection.
binary_tree* tree; /* why use a pointer to a pointer? */
Unless you intend to change the value of the pointer, this is extra work you don't want to be doing. All those "(*tree)->member" expressions are not needed if you follow the usual conventions, and I'm not convinced that you understand what "&(*tree)->left" is doing.
I'm not saying that you should never use a pointer to a pointer, I've done it myself, however you should only do it when there is a reason to be changing the value of the referenced pointer, or with a volatile pointer that might be changed by some external actor; this is unlikely and fairly rare outside of garbage collected and compacted pools (strings in some BASIC interpreters, for example) and the like.
Keep in mind that the "left" subtree of a node in the tree is a binary tree itself; it has both left and right nodes. You need to write a function that deletes a subtree at and below a given node. Once that's understood, removal of the left subtree below a node is as simple as:
void delSubtree(NodeT* subRoot)
{
if (subRoot != NULL)
{
delSubtree(subRoot->left);
delSubtree(subRoot->right);
free(subRoot);
}
}
void delLeftSubtree(NodeT* root)
{
if (root != NULL)
{
delSubtree(root->left);
root->left = NULL;
}
}
If this is homework, you should be solving these problems yourself, and I'm doing you no favors in giving you code samples. Understanding how to use pointers and linked data structures (lists, trees, and other graphs) is essential to becoming an accomplished C programmer.
So I am trying to learn how to create a binary tree in C so far I have got this.
void addRecordsToTree(struct date *in, struct date *root) {
if (root == NULL) {
root = malloc(sizeof(struct date));
root = in;
return;
} else {
//Right side of tree processing
if (compareTwoRecords(in, root) >= 0) {
addRecordsToTree(in, root->right);
return;
} else {
root->right = in;
return;
}
//Left side of tree processing.
if (compareTwoRecords(in, root) < 0) {
addRecordsToTree(in, root->left);
return;
} else {
root->left = in;
return;
}
}
}
int main() {
loadFiles();
struct date treeRoot;
struct date *old = malloc(sizeof(struct date));
old = loadContentsIntoHeap(files[file2014]);
addRecordsToTree(&old[0], &treeRoot);
addRecordsToTree(&old[1], &treeRoot);
addRecordsToTree(&old[2], &treeRoot);
addRecordsToTree(&old[3], &treeRoot);
addRecordsToTree(&old[4], &treeRoot);
addRecordsToTree(&old[5], &treeRoot);
printRecord(7, old);
return 0;
}
The problem is when I check the state of the program in a debugger there is just jumbled up data. I think it could be a type problem somewhere, I find pointers are bit of a mind boggling concept. Im not sure if I have used them right. So here is a screen shot of the debugger.
As you can see at the bottom struct called 'old' is the data I am trying to make the tree out of and treeRoot is where I am trying to place it but I can't understand why I get these garbage values.
Also what is up with the memory address of left and right? am I not creating them correctly.
Another observation I made is when I watch my code in the debugger it seems that root is never == NULL and never gets set, why?
You just did the following:
int x = 2;
int y = x;
y = 5;
Is the second line here necessary or the third one. It is a totally illogical program if you did this. You just did the same thing with a pointer instead of integer. You firstly had a pointer to the base address of dynamic memory then you just overwrote it by initializing it the second time.
And, the iterative approach is far better in comparison to the recursive one. I share the code for inserting a node in a binary tree both recursively and iteratively:
void insert(struct node *temp, struct node **root)
{
while (*root != NULL)
root = (*root)->element < temp->element ? &(*root)->left : &(*root)->right;
*root = temp;
}
#if 0
/* Recursive approach */
void insert(struct node *temp, struct node **root)
{
if(*root == NULL)
*root = temp;
else if ((*root)->element < temp->element)
insert(temp, &(*root)->left);
else
insert(temp, &(*root)->right);
}
#endif
void create_node(int x, struct node **root)
{
struct node *temp = (struct node *) malloc(sizeof(struct node));
if (temp == NULL)
printf("Unable to allocate memory. Free some space.\n");
else
{
temp->left = NULL;
temp->right = NULL;
temp->element = x;
insert(temp, root);
}
}
int main()
{
struct node *root = NULL;
create_node(1, &root);
create_node(2, &root);
create_node(3, &root);
return 0;
}
I saw an additional Problem in your "addRecordsToTree"-function:
the IF-block of the
"//Right side of tree processing"
will allways return from the function. regardless wether the "IF"-Expression is true or false.
So your left-leaves of thew tree will never be inserted. So you probalby should check/debug that function.
My code is not printing the elements of binary search tree:
//x is the element to be inserted
//structure of program
typedef struct BST
{
int info;
struct BST *left;
//pointer to left node
struct BST *right;
//pointer to right node
}
bst;
//global root variable
bst *root;
void insert(int x)
{
bst *ptr,*sptr=root;
ptr=(bst*)malloc(sizeof(bst));
ptr->info=x;
if(root==NULL)
{
ptr->left=ptr->right=NULL;
root=ptr;
}
while(sptr!=NULL)
{
if(x<sptr->info)
{
sptr=sptr->left;
}
else
sptr=sptr->right;
}
sptr=ptr;
}
edit:
//following is the show function
void show()
{
bst *ptr=root;
while(ptr!=NULL)
{
//it will print untill the ptr is null
printf("%d",ptr->info);
ptr=ptr->left;
ptr=ptr->right;
}
}
Where is the value of root coming from? You're not passing in the value anywhere? Also, it is tough to help when we don't know the design of type bst.
It appears that you have the right idea. Create a node, and give it some data. If the root is null, then the new value is the root of the BST. After that you go ahead and find the first null node either in the left or right subtree of the root using the standard BST behavior. Finally, when you reach the end you go ahead and insert the last node in the proper place.
void insert(int x)
{
bst *ptr, *sptr=root; //<-- the value right here?
ptr = malloc(sizeof(bst));
ptr->info = x;
if(root == NULL)
{
ptr->left=ptr->right=NULL;
root=ptr;
}
while(sptr!=NULL)
{
if(x<sptr->info)
{
sptr=sptr->left;
}
else
sptr=sptr->right;
}
sptr=ptr; // <-- What is this line trying to do?
}
However, where did your updated tree go?
Since in C everything is passed by value, you're running into the problem where you're not seeing your updated tree after you leave this function. You need to go ahead and change the function to return a bst* type, and also maintain the root node during the entire function. Now the first line of code (*sptr = root) makes more sense! Finally, you were not setting the left and right fields of ptr to NULL. This means you were jumping over your if statements.
bst* insert(int x, bst *root)
{
bst *ptr, *sptr=root;
ptr = malloc(sizeof(bst));
ptr->left = NULL;
ptr->right = NULL;
ptr->info = x;
if(root == NULL)
{
ptr->left=ptr->right=NULL;
root=ptr;
return root;
}
while(sptr!=NULL)
{
if(x<sptr->info)
{
sptr=sptr->left;
}
else
sptr=sptr->right;
}
sptr=ptr;
return root;
}
What about the next function?
I just started looking at this one too. I am not used to the global variables in c, so I will go ahead and make two modifications. Let's make this recursive, and pass in the value of the root rather than using the global.
void show(bst *root)
{
if(root == NULL){
return;
}
printf("%d",root->info);
show(root->left);
show(root->right);
}
This will take in some value, and solve the tree recursively, and print as it reaches each node. Thus, it will print the root node (if it exists), and then print the left entire left subtree before it prints the right subtree.
Finally, looking at your main
I added the local variable root and thus you will have to remove the global variable named root outside of your main function. I also set the value of it to null so your first insert will fire correctly.
int main()
{
int i,n,x;
bst *root = NULL; //<-- I added this line of code to remove the global
puts("Enter number of elements");
scanf("%d",&x);
for(i=0;i<x;i++)
{
puts("Enter elements");
scanf("%d",&n);
root = insert(n, root);
}
show(root);
return 0;
}
I hope this helps!
I am writing a program that is a linked list of binary search trees. We are supposed to search for a number in the trees and print the tree and line number found. Because of this, we are supposed to use a Breadth-First Search function. I am getting a segmentation fault in my dequeue function and I am unsure why.
These are my structures:
typedef struct BST {
int value;
int treeNum;
struct BST* left;
struct BST* right;
}BST;
typedef struct rootList{
struct BST* root;
struct rootList* next;
}rootList;
typedef struct bfsQ{
struct BST* treeNode;
struct bfsQ* next;
}bfsQ;
This is my BFS function:
void BFS(rootList* listHead, int searchValue)
{
if(listHead->root == NULL)
{
printf("%d/tNO/tN/A/tN/A\n", searchValue);
}
else
{
bfsQ* newQueue = NULL;
BST* temp = NULL;
newQueue = malloc(sizeof(bfsQ));
newQueue->next = NULL;
enqueue(&newQueue, listHead->root);
while(newQueue != NULL)
{
temp = dequeue(&newQueue);
printf("Did this work?");
if(temp->value == searchValue)
printf("HI I WAS FOUND");
else
{
if(temp->left != NULL)
enqueue(&newQueue, temp->left);
if(temp->right != NULL)
enqueue(&newQueue, temp->right);
}
}
BFS(listHead->next, searchValue);
}
}
This is my enqueue:
void enqueue(bfsQ** qHead, BST* new_tree_node)
{
bfsQ *temp = malloc(sizeof(bfsQ));
BST *node;
temp->treeNode = new_tree_node;
temp->next = *qHead;
*qHead = temp;
node = temp->treeNode;
printf("%d\n", node->value);
}
This is my dequeue:
BST* dequeue(bfsQ** qHead)
{
bfsQ *temp, *first;
BST *newBST;
temp = (*qHead);
while(temp->next != NULL)
{
printf("THIS IS NOT NULL YET\n");
temp = temp->next;
}
first = temp;
newBST = first->treeNode;
free(temp);
return first->treeNode;
}
What am I doing wrong? The enqueue is working correctly, however my dequeue is not storing correctly.
EDIT: Apparently I need to:
"This function implements a variant of a level by level search or formally
called as the BREADTH FIRST SEARCH.
-> This function searches for a given value in the binary trees and it does that
by searching for level 1 in each binary trees, then moving on to level 2 if
it fails to find it that value in level 1 and so on.
-> Basically, you have to search for a given value in all the binary trees, one
level at a time, in the linked list simultaneously."
So I'm not sure if I need to search the whole tree, then move on, or look at each tree, line by line.
From the superficial look I had into the code, it looks generally ok (though I would have implemented some parts differently), but the last lines in dequeue() are certainly wrong:
first = temp;
newBST = first->treeNode;
free(temp);
return first->treeNode;
Accessing first->treeNode in the last line is catastrophic: first holds an address that has already been freed (temp and first refer to the same memory location). I think you wanted to return newBST instead:
return newBST;
You might as well throw first away, as it seems useless, and turn that into:
newBST = temp->treeNode;
free(temp);
return newBST;