Repair tree structure in c - c

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.

Related

How can i delete multiple nodes of a BST in c?

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).

An error occurs during the implementation of the linked list tree

enter code here
#include <stdio.h>
#include <stdlib.h>
typedef struct _node {
int data;
struct _node* rightChild;
struct _node* leftChild;
}Node;
Node* create(int data) { // create node function
Node* node = (Node*)malloc(sizeof(node));
node->rightChild = NULL;
node->leftChild = NULL;
node->data = data;
return node;
}
void Inorder(Node* ptr) { // travel
if (ptr)
{
printf("%c ", ptr->data);
Inorder(ptr->leftChild);
Inorder(ptr->rightChild);
}
}
int main(void)
{
Node* node[300];
for (int i = 1; i < 300; i++) {
if (i == 1) {
node[i] = create(i);
}
else {
if (i % 2 == 0) {
node[i / 2]->leftChild = create(i);
}
else {
node[i / 2]->rightChild = create(i);
}
}
}
Inorder(node[10]);
}
I would like to implement a binary tree using a Node* array, rather than taking variables input one by one. But I keep getting errors in that area. Thanks for the advice.Which part do I need to modify to make that part implemented through a for statement? As far as I understand, both the left and right parts of the node array have passed values, so why am I getting an error?
The only node[i] you assign to is node[1]. All other nodes are linked via the the leftChild or rightChild fields.
You could fix this by doing, for example:
node[i] = create(i);
node[i / 2]->leftChild = node[i];
but I this is a bit roundabout, because you now have the same data – the handle to a node — in two different places.
My guess is that what you really want is a plain array of node structures, which are then linked via pointers into the array:
Node node[300] = {{0}};
node[1].data = 1;
for (int i = 2; i < 300; i++) {
node[i].data = i;
if (i % 2 == 0) {
node[i / 2].leftChild = &node[i];
} else {
node[i / 2].rightChild = &node[i];
}
}
This creates a flat array of nodes, where the nodes are linked like a binary tree. For example, node[1].leftChild is a pointer to node[2]. You can use regular tree functions by passing &node[1] as head:
Inorder(&node[1]);
(What you call Inorder is really a pre-order traversal.)
The advantage is that you don't need to create and allocate anything. When main ends, the whole tree is gone without needing to free. (It also gets rid of a bug in create, where you allocate space for a pointer only, not for a node; it should be node = malloc(sizeof(*node));.)
Perhaps that's not what you want, but the bug in your code comes from accessing node[2] when it hasn't been set.

Deallocating binary-tree structure in C

I have a linked list, I guess a tree looks like this:
-> grandma
-> dad
-> me
-> sister
-> niece
-> brother
-> uncle
-> cousin
and I have a struct as following
struct Node{
Node *parent;
Node *next;
Node *child;
}
How would I free that linked list?
My idea is to do a depth first search and deallocate each node?
Recursive depth-search (DFS): You're right, it's a good way to dealocate binary-tree memory:
remove(node):
if node is null: return
//else
remove(left node)
remove(right node)
free(node)
Iterative solution:
https://codegolf.stackexchange.com/questions/478/free-a-binary-tree
Since you don't want to use any recursive solution, there you can find well-described iterative one.
You can optimize allocation/deallocation of the tree.
Imagine, you want to create tree with 20 or 30 persons. You can allocate an array of 30 Node structs:
size_t currentArraySize = 30;
Node* nodes = (Node*)malloc(currentArraySize * sizeof(Node));
size_t nextFreeIndex = 0;
To add new element you can write simple function:
Node* allocateNode()
{
// Oops! There's not more memory in the buffer.
// Lets increase its size.
if (nextFreeIndex >= currentArraySize) {
currentArraySize *= 2;
Node* newNodes = (Node*)realloc(nodes, currentArraySize * sizeof(Node));
// Should correct pointers (thanks to user3386109)
if (newNodes != nodes) {
for (size_t i = 0; i < nextFreeIndex; i++) {
if (newNodes[i]->parent != NULL)
newNodes[i]->parent -= nodes += newNodes;
if (newNodes[i]->next != NULL)
newNodes[i]->next -= nodes += newNodes;
if (newNodes[i]->child != NULL)
newNodes[i]->child -= nodes += newNodes;
}
}
}
return nodes[nextFreeIndex++];
}
To deallocate all nodes you can just free the single pointer nodes.
Now the code looks a little scary as wrote user3386109, so we may simplify it a little:
Node* allocateNode()
{
// Oops! There's not more memory in the buffer.
// Lets increase its size.
if (nextFreeIndex >= currentArraySize) {
currentArraySize *= 2;
Node* newNodes = (Node*)realloc(nodes, currentArraySize * sizeof(Node));
// Should correct pointers (thanks to user3386109)
if (newNodes != nodes)
correctPointers(newNodes, nodes);
}
return nodes[nextFreeIndex++];
}
#define correctPointer(pointer, oldOffset, newOffset) if (pointer != NULL) { \\
pointer -= oldOffset; \\
pointer += newOffset; \\
}
void correctPointers(Node* newNodes, Node* nodes)
{
for (size_t i = 0; i < nextFreeIndex; i++) {
correntPointer(newNodes[i]->parent, nodes, newNodes);
correntPointer(newNodes[i]->child, nodes, newNodes);
correntPointer(newNodes[i]->next, nodes, newNodes);
}
}
Iterative version, inspired by Day–Stout–Warren algorithm:
void removetree(Node *node)
{
while(node != NULL)
{
Node *temp = node;
if(node->child != NULL)
{
node = node->child;
temp->child = node->next;
node->next = temp;
}
else
{
node = node->next;
remove(temp);
}
}
}
This algorithm somewhat like tries to convert the tree into a list single-linked with next pointers, which is very simple to destroy just by iterative unlinking and destroying the first item. However it never completes the conversion, because it unlinks and removes the head node as soon as it can, despite the rest of tree not being converted yet. So to say, it interleaves a relink step with unlink-and-destroy step.
We test with the if instruction whether the first (head) node has any children. If so, we make its child a new head and the current node becomes the new head's next node. This way we have one more next link in the first-level list. What was 'next' to the now-head node becomes a child to a previous-head node, which is now the head's first next.
On the other hand if the head node has no children, it may be removed and its next becomes a new head.
These two steps are iterated by the while loop until all children are converted into siblings and removed afterwards.
You may use recursive solution
free(root)
{
if (root->next == null)
{
free(node)
}
free(root->left)
free(right->)
}

Stuck with deleting node from tree

I'm trying to build a max heap in VC++ using Visual Studio 2008 v9.0.30729.1 SP.
In the tree, each node looks like:
typedef struct node{
struct data_t *data;
struct node_t *left;
struct node_t *right;
}node_t;
A single node creation logic goes like this:
node_t* createNode(int id, int pID, float probability)
{
node_t *temp = (node_t *)malloc(sizeof(node_t));
data_t *data = (data_t *)malloc(sizeof(data_t));
data->id = id;
data->pID = pID;
data->probability = probability;
temp->data = data;
temp->left = 0;
temp->right = 0;
return temp;
}
I have managed to create and insert elements in the tree (insertion logic working fine). I'm stuck with the logic of removing a node (a leaf, to be precise) from this tree.
I've tried four different approaches for the same:
node_t* deleteLeaf(node_t* heap)
{
node_t* leaf;
if((heap->left==0) && (heap->right==0))
{
//heap = 0; //APROACH 1
//heap->data = 0; //APROACH 2
return heap;
}
else if((heap->left!=0) && (heap->right==0))
{
leaf = deleteLeaf(heap->left);
}
else
{
leaf = deleteLeaf(heap->right);
}
//leaf = 0; //APROACH 3
//free(leaf); //APROACH 4
return leaf;
}
(Uncomment APPROACH 1/2/3/4 for the desired effect).
None of this seems to work. I need to assign a zero/null value to the left/right pointer of the previous node.
How to make this work? Please help.
To delete a node in a tree you need to
free the memory and do the cleanup for the node
fix the pointer you used to reach the node, making it NULL
the part 2 can be solved in two ways:
A) the parent does the fixing
B) the deletion routine receives the address of the address of the node (extra level of indirection).
For solution A the code is simply
void deleteNodeA(Node *p) {
if (p) {
// Here we don't really need part 2 because
// we're going to destroy the whole node containing
// the pointers anyway.
deleteNodeA(p->left); // add p->left = NULL if you like
deleteNodeA(p->right); // add p->right = NULL if you like
free(p->data);
free(p);
}
}
but the caller needs to fix the pointer used to reach the node. For example like
Node *p = root, *parent = NULL;
while (p && (p->left || p->right)) {
// Not a leaf... go left if possible o right otherwise
parent = p;
p = p->left ? p->left : p->right;
}
// 2: Fix the pointer in parent
if (parent) {
if (p == parent->left) {
parent->left = NULL;
} else {
parent->right = NULL;
}
} else {
// No parent... this was the root of the tree
root = NULL;
}
deleteNodeA(p);
The solution B looks like:
void deleteNodeB(Node **p) { // Note the double pointer
if (*p) {
deleteNode(&((*p)->left)); // Note the &
deleteNode(&((*p)->right)); // Note the &
free((*p)->data);
free(*p);
*p = NULL; // (2): fixing the pointer
}
}
and for example code deleting a leaf of the tree is
Node **p = &root;
while ((*p) && ((*p)->left || (*p)->right)) {
// Not a leaf... go left if possible o right otherwise
p = ((*p)->left) ? &((*p)->left) : &((*p)->right));
}
deleteNodeB(p);
Instead of writing 4 random lines of code and calling them "approaches", try actually specifying a function that does something meaningful. A function that takes a heap as an argument should be called DeleteHeap, not DeleteLeaf. Since it deletes a heap, there's nothing for it to return. So, how do you delete a heap? Well, if the heap is a leaf (it has no left or right subtree), delete that, else delete the subtrees by calling DeleteHeap recursively. Code that and you're done.
Edit:
You left a comment:
deleteLeaf is supposed to delete the last element of the tree at the
last level. The value returned should be the data contained in the
deleted leaf.
Well, that's news. We aren't mind-readers. Your question didn't say this, and the function name and signature are wrong for this, too.
Let's start with the name -- DeleteRightmostLeaf. And the return type ... data_t*. Even the argument type is wrong ... it should be heap_t**, because we have to store a NULL into the pointer.
So, DeleteRightmostLeaf takes a pointer to a pointer to a heap. If that heap is a leaf node, store NULL in the pointer to it, extract its data pointer, free the node (in that order ... otherwise you're accessing deleted memory, which isn't allowed), and return the data pointer.
If the heap isn't a leaf node, then call DeleteRightmostLeaf recursively on the pointer to its rightmost subtree -- the right subtree if that's not NULL, else the left subtree. Voila, you're done.
Note that, in both cases, it's very easy to come up with the answer if one just thinks clearly about what they need to do.
As a bonus, here's an iterative solution. I haven't tested or even compiled this.
data_t* DeleteRightmostLeaf(node_t** pheap)
{
node_t* pnode = *pheap;
if (!pnode)
return NULL; // empty heap
while (pnode->left || pnode->right)
{
pheap = pnode->right ? &pnode->right : &pnode->left;
pnode = *pheap;
}
*pheap = NULL;
data_t* pdata = pnode->data;
free(pnode);
return pdata;
}
Try this modification of your method:
node_t* deleteLeaf(node_t* heap)
{
if (!heap)
return 0;
if (heap->left!=0)
deleteLeaf(heap->left);
if (heap->right!=0)
deleteLeaf(heap->right);
if (heap->data)
free(heap->data); // free data
free(heap); // free leaf
heap = 0;
return heap;
}
One question: which value should be returned by this function? (now it always returns 0).
It is hard to understand what you are trying to do (we haven't description of the function, examples of expected results and so on). So, I suspect, that code above is not solution. But it might be first step in understanding of the problem.

Problem with pointers in binary search tree deletion

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.

Resources