I am trying to implement binary search tree operations and got stuck at deletion.
11
/ \
10 14
Using inorder traversal as representation of tree initially output is 10 11 14.
Deleting node 10, output expected is 11 14 but I am getting 0 11 14.
Deleting node 14, output expected is just 11 but I am getting 0 11 67837.
Please explain why I am getting wrong output. I am not looking for any code :).
typedef struct _node{
int data;
struct _node *left;
struct _node *right;
} Node;
Node* bstree_search(Node *root, int key)
{
if(root == NULL){
return root;
}
// Based on binary search relation, key can be found in either left,
// right, or root.
if(key > root->data)
return bstree_search(root->right, key);
else if(key < root->data)
return bstree_search(root->left, key);
else
return root;
}
void bstree_insert(Node **adroot, int value)
{
// since address of address(root is itself address) is passed we can change root.
if(*adroot == NULL){
*adroot = malloc(sizeof(**adroot));
(*adroot)->data = value;
(*adroot)->right = (*adroot)->left = NULL;
return;
}
if(value > (*adroot)->data)
bstree_insert(&(*adroot)->right, value);
else
bstree_insert(&(*adroot)->left, value);
}
void bstree_inorder_walk(Node *root)
{
if(root != NULL){
bstree_inorder_walk(root->left);
printf("%d ",root->data);
bstree_inorder_walk(root->right);
}
}
void bstree_delete(Node **adnode)
{
//Node with no children or only one child
Node *node, *temp;
node = temp = *adnode;
if((*adnode)->right == NULL || (*adnode)->left == NULL){
if((*adnode)->right == NULL){
*adnode = (*adnode)->left;
}else{
*adnode = (*adnode)->right;
}
}else{ // Node with two children
}
free(temp);
}
int main()
{
Node *root = NULL;
Node *needle = NULL;
int i,elems[] = {11,10,14};
for(i = 0; i < 3; ++i)
bstree_insert(&root,elems[i]);
bstree_inorder_walk(root);
printf("\n");
needle = bstree_search(root, 10);
bstree_delete(&needle);
bstree_inorder_walk(root);
printf("\n");
needle = bstree_search(root, 14);
bstree_delete(&needle);
bstree_inorder_walk(root);
printf("\n");
}
Please explain why I am getting wrong
output.
Your delete function must also change the parent of the deleted Node. For example, when you delete the node holding 10, you must set the root Node's left child to NULL. Since you don't do this, when you later traverse the tree, you print out data that has already been freed.
I did not look at any code other than delete, so I can't make any guarantees about it working once this change is made.
You're getting wrong output because your deletion code is buggy (okay, maybe that's stating the obvious).
To delete from a binary search tree, you first find the node to be deleted. If it's a leaf node, you set the pointer to it in its parent node to NULL, and free the node. If it's not a leaf node, you take one of two leaf nodes (either the left-most child in the right sub-tree, or the right-most child in the left sub-tree) and insert that in place of the node you need to delete, set the pointer to that node in its previous parent to NULL, and delete the node you've now "spliced out" of the tree.
A couple of things really quick,
first when you allocate the node, you really should be doing the malloc on the sizeof the type (ie Node).
Second, if you have 2 children it looks like you are not really deleting the node and rebuilding the search tree by promoting one of the children.
Other people have already got you other obvious errors.
Related
i have to delete some nodes of this BST
struct node {
char *value;
struct node *p_left;
struct node *p_right;
int usable;
};
the nodes that i have to delete are the ones with usable set to 0.
my question is, is it possible to make a sweep of the tree and delete all the nodes with usable == 0? all the resources i found online are about deleting a node containing a certain key, i tried to apply those but they didn't work
--edit:
the remove node function that i implemented was fine:
struct node* deleteNode(struct node* root, char *key) {
if (root == NULL)
{
return root;}
int cmp_result = strcmp(key, root->value);
if (cmp_result < 0)
root->p_left= deleteNode(root->p_left, key);
else if (cmp_result>0)
root->p_right= deleteNode(root->p_right, key);
else{
if (root->p_left==NULL) {
struct node *temp = root->p_right;
free(root);
return temp;
} else if(root->p_right==NULL){
struct node *temp = root->p_left;
free(root);
return temp;
}
struct node* temp = minValueNode(root->p_right);
strcpy(root->value, temp->value);
root->p_right= deleteNode(root->p_right, temp->value);
}
return root;
}
the problems arose because i called this function while traversing the tree, changing the structure of the tree while i'm using it
void pos2(struct node *head, char exactchar, int n)
{
if( head != NULL ) {
pos2(head->p_left, exactchar, n);
if (head->value[n]!=exactchar){
head = deleteNode(head, head->value);}
pos2(head->p_right, exactchar, n);
}
}
like this function that deletes a node if it has a word without a determined char in a determined position in it
is it possible to make a sweep of the tree and delete all the nodes with usable == 0?
Of course.
all the resources i found online are about deleting a node containing a certain key, i tried to apply those but they didn't work
I have no idea what, specifically, you tried. However, algorithms aimed at deleting the node having a specific key clearly do not solve the problem you have posed. They will use the BST-ness of the tree to efficiently find the specific node to delete, if it is present, and delete just that node.
Since your flag does not have a functional relationship with the keys on which the BST is ordered, you need to traverse the whole tree and delete every node you find that satisfies your criterion for doing so. Operationally, I would probably structure that as a depth-first traversal with post-order deletions (that is, consider whether to delete a given node after processing both its subtrees).
I am trying to write a recursive function that, given the root of a binary tree and a key, searches for the key using in-order traversal. The function returns NULL if the node with the key isn't found; otherwise it returns the node containing the key.
What I'm having trouble with is returning the node that contains the key. Every time I call the function and the key is in the binary tree, the function returns NULL. It feels like the result keeps getting overwritten by the initialization in the first line in the function.
Here's the in-order search function:
typedef struct treeNode
{
int data;
struct treeNode *left, *right;
} TreeNode, *TreeNodePtr;
typedef struct
{
TreeNodePtr root;
} BinaryTree;
TreeNodePtr inOrderKey(TreeNodePtr root, int key)
{
TreeNodePtr node = NULL;
if (root != NULL)
{
node = inOrderKey(root->left, key);
if(key == root->data)
{
node = root;
return node;
}
node = inOrderKey(root->right, key);
}
return node;
}
Here's the main function:
int main()
{
FILE * in = fopen("numbst.txt", "r");
BinaryTree bst;
bst.root = NULL;
int num;
fscanf(in, "%d", &num);
while (num != 0)
{
if (bst.root == NULL)
bst.root = newTreeNode(num);
else
{
TreeNodePtr node = findOrInsert(bst, num);
}
fscanf(in, "%d", &num);
}
printf("\nThe in-order traversal is: ");
inOrder(bst.root);
printf("\nThe pre-order traversal is: ");
preOrder(bst.root);
TreeNodePtr keyNode;
int count = 0;
keyNode = inOrderKey(bst.root, 9);
if (keyNode != NULL)
count = 1;
else
count = 0;
if (count == 1)
printf("\n\n%d exists in the binary tree. In order traversal was used.\n", 9);
else
printf("\n\n%d doesn't exist in the binary tree. In order traversal was used.\n", 9);
return 0;
}
The in-order traversal of the binary tree I'm working with is: 1 2 3 4 5 7 9 21
The pre-order traversal of the binary tree is: 4 1 2 3 7 5 21 9
I'm testing the function using 9 and 31.
This code:
node = inOrderKey(root->left, key);
if(key == root->data)
{
node = root;
return node;
}
node = inOrderKey(root->right, key);
first uses inOrderKey to search the left subtree. Then it ignores the result.
Then it tests whether the current node contains the key. If it does, it returns to its caller. If the caller was itself (this is in a recursive call, not the original), the caller likely ignores the result.
Then it uses inOrderKey to search the right tree. Then it returns the result.]
Ultimately, the node containing the key will be returned only if it was in the rightmost path. If it is in the left subtree of any node, it will be ignored.
To fix this, after each call to inOrderKey, test whether the returned value is a null pointer. If it is not, return it immediately instead of going on.
The problem you have is that you insist in navigating the whole tree without checking if you found the key already. In
TreeNodePtr inOrderKey(TreeNodePtr root, int key)
{
/* don't declare a local you don't know
* yet if you are going to use */
/* better to check the opposite */
if (root == NULL)
return NULL; /* no tree, nothing can be found */
TreeNodePtr node = inOrderKey(root->left, key);
if (node) return node; /* we found it in the left child */
if(key == root->data) { /* check here */
/* you found it in this node */
return root;
}
/* last chance, right child :) */
return inOrderKey(root->right, key);
}
the verifications are made, so this should work (I've not tested it, as you didn't post a complete and verifiable example, my apologies for that)
[edited - updated to use in order traversal]
Traverse left. If key not found, then check root, if key doesn't match, then recurse right.
TreeNodePtr inOrderKey(TreeNodePtr root, int key)
{
TreeNodePtr node = NULL;
if (root)
{
node = inOrderKey(root->left, key);
if (node) {
return node;
}
if (key == root->data)
{
return root;
}
node = inOrderKey(root->right, key);
}
return node;
}
I have a tree structure in c (quadtree) which I want to clean to avoid long tree branches. Here is an example:
Instead of this tree structure,
I want to clean up the tree to get this structure (Same information, less memory consumption, faster tree walks).
Here the red node is the root of the tree. Blue nodes are empty and black nodes are tree nodes which carry information.
My tree has the following structure in c:
typedef enum{particle, pseudo_particle} node_type;
typedef struct{
double m;
double x[DIM];
int to_delete;
} Particle;
typedef struct{
double x_min[DIM];
double x_max[DIM];
} tree_box;
typedef struct tree_node{
Particle p;
tree_box box;
node_type node;
struct tree_node *child[4];
} tree_node;
The function which cleans up the tree
void clean_tree(tree_node *t){
if(t != NULL){
for(int i=0; i<4; i++){
clean_tree(t->child[i]);
}
// Operation on *t
if(t->node != particle){
int child_counter = 0;
int d = 0;
for(int i=0; i<4; i++) {
if(t->child[i] != NULL) {
if(t->child[i]->p.to_delete == TRUE){
free(t->child[i]);
t->child[i] = NULL;
}
else {
child_counter++;
d=i;
}
}
}
if(child_counter == 0) {
t->p.to_delete = TRUE;
}else if (child_counter == 1) {
t = t->child[d];
free(t->child[d]);
t->child[d] = NULL;
}
}
// End of operation on *t
}
}
But here is the problem: After calling clean_tree() my tree structure is no longer existent. The whole tree gets deleted. But why? Does someone see my error?
I verified your code.
What you are doing is that you are traversing the tree and when you found that all the child nodes of a three node are null you are setting it to be delete or you are deleting the parent node who’s all the child nodes are null or deleted. Till that I can understand you did right. But when there is only one child node exist and rest are null or deleted you are deleting child of it with same index, which is not understandable for me.
if(child_counter == 0) {
t->p.to_delete = TRUE;// Here you are setting the parent node to be deleted while you found that all the child nodes are null or you deleted them in the above
//but instead of this you should delete the node here itself like free(t); and you don’t need to call the method `clear_tree` again
}else if (child_counter == 1) {
t = t->child[d]; //as t is a local pointer to the current function(recursive) function. Once it return to its previous call the t in that function is holding the address of different node
free(t->child[d]); //why are you deleting this node? By doing it you are deleting the whole tree
//this child node might have a branches in it. Instead of deleting it you should store its address in parents node’s child node list or if this is the only node of the tree just leave it
t->child[d] = NULL;
}
Your problem is exactly at the above code. Just follow my comments and it might help you to fix your issue.
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!
This is homework for my first class in c. It focuses on dynamic allocation in c, in the form of a bst.
I have to have a dynamically allocated BST, recursively implemented. I know that my traversal works correctly, and am having trouble inserting nodes. I only ever have the root node, and every other node seems to be set to NULL. I think that I can't print the rest of the nodes when traversing, because I am trying to access the data member of a NULL struct. My code so far is as follows:
void insert_node(TreeNode** root, int toInsert){
if(*root==NULL){
TreeNode *newnode = (TreeNode *)malloc(sizeof(TreeNode));
newnode->data = toInsert;
newnode->left = NULL;
newnode->right = NULL;
}
else if(toInsert > (*root)->data){ //if toInsert greater than current
struct TreeNode **temp = (TreeNode **)malloc(sizeof(struct TreeNode*));
*temp = (*root)->right;
insert_node(temp, toInsert);
}
else{ //if toInsert is less than or equal to current
struct TreeNode **temp = (TreeNode **)malloc(sizeof(struct TreeNode*));
*temp = (*root)->left;
insert_node(temp, toInsert);
}
}
void build_tree(TreeNode** root, const int elements[], const int count){
if(count > 0){
TreeNode *newroot = (TreeNode *)malloc(sizeof(TreeNode));
newroot->data = elements[0];
newroot->left = NULL;
newroot->right = NULL;
*root = newroot;
for(int i = 1; i < count; i++){
insert_node(root, elements[i]);
}
}
I'm sure it's only one of many problems, but I get segmentation faults on any line that uses "(*root)->data", and I'm not sure why.
As a side note, despite getting segmentation faults for the "(*root)->data" lines, I'm still able to printf "(*root)->data". How is it possible to print the value, but still get a segmentation fault?
It's messy. Some things that might help
1) Don't need to use TreeNode*, pointer to pointer, as argument. Use jsut the TreeNode. (something went wrong here, as it's some feature from the text editor, consider and additional * after each TreeNode in this line)
2) Not a strict rule, but as best practice avoid using the first node of a linked list to store actual values. Use just as the header of your list. Reason is, if you need to delete this node, you don't lose the list. Just a tip
3) In your first function, if *root==NULL, I'd rather make the function fail than adding it to a temporary list (that's being lost in the current code, see that it adds the value to a list that is not being passed outside the function.
4) Well, you are actually making it go to the right if the new value is greater than the node, to the left if it's smaller than the node, but it never stops. See this example:
Suppose you have the list 1->3->4. Now you want to insert 2. What the algorithm will do? keep trying to insert in the 1 node and 3 node, switching between them, but never actually inserting anything.
Solution: as you will build this list bottom up, your list will always be sorted (inf you insert nodes correctly). So you just need to check if the next node is higher, and if it is, insert right where you are.
5) If you're passing a TreeNode *root as argument (on the 2nd function), you shouldn't have to recreate a new list and make root=newlist. Just use the root.
All of this would result in (didn't test, might be some errors):
void insert_node(TreeNode* root, int toInsert){
if(root==NULL){
printf("Error");
return;
}
TreeNode* temp = root; //I just don't like to mess with the original list, rather do this
if(temp->right!=NULL && toInsert > temp->right->data){ //if toInsert greater than next
insert_node(temp->right, toInsert);
}
else{ //if toInsert is less or equal than next node
TreeNode* temp2 = temp->right; //grabbing the list after this node
temp->right=(TreeNode*)malloc(sizeof(TreeNode)); //making room for the new node
temp->right->right=temp2; //putting the pointer to the right position
temp->right->left=temp; //setting the left of the next node to the current
temp->right->data=toInsert;
}
}
void build_tree(TreeNode* root, const int elements[], const int count){
if(count > 0){
for(int i = 0; i < count; i++){
insert_node(root, elements[i]);
}
}
}