How can I free this tree effectively? That algorithm should work for any given node in such tree. So I'll have pointer to node, and that node will be "root" node. And I want to free everything below that node.
Every node in tree is this struct:
typedef struct tag
{
struct tag* parent;
struct tag* nextSibling;
struct tag* previousSibling;
struct tag* firstChild;
struct tag* lastChild;
char* name;
char* text;
}node;
I imagine this would work. But in reality, Dariusz is correct. You just use a valid tree traversal, and perform your operation on each node.
The question changed: And since you want this to operate on any node in the tree, just find the root first. It's much easier to write a tree traversal that progresses in one direction, than up and down the tree.
You've changed the question from deleting a tree, to deleting a subset of a tree. So, instead, let's do this. Remove the element from the tree first (remove_node). and then perform the same free that we would have done before.
void remove_node(node *self) {
if (self->previousSibling)
self->previousSibling->nextSibling = self->nextSibling;
if (self->nextSibling)
self->nextSibling->previousSibling = self->previousSibling;
if (self->parent && self->parent->firstChild == self)
self->parent->firstChild = self->nextSibling;
if (self->parent && self->parent->lastChild == self)
self->parent->lastChild = self->previousSibling;
}
void free_node(node *self) {
// Free one node. Perhaps this is:
free(self->name);
free(self->text);
free(self);
}
void iterate_nodes(node *root, void op(node *self) ) {
if (root == NULL)
return;
iterate_nodes(root->nextSibling, op);
iterate_nodes(root->firstChild, op);
op(root);
}
int main() {
node *node = NULL; // Some node in the tree...
remove_node(node);
iterate_nodes(node, free_node);
}
Use any of the standard tree-traversal mechanisms and delete all elements.
http://en.wikipedia.org/wiki/Tree_traversal
You can use a standard post-order tree traversal algorithms to free the whole tree. To make it work from any given node, just start by traversing all of the parent links to the root. For example:
void free_tree(node *n)
{
// Find the root node of the tree
while(n->parent)
n = n->parent;
free_tree_helper(n);
}
void free_tree_helper(node *n)
{
// Free all children of this node in post-order traversal
node *child = n->firstChild;
while(child)
{
// Save the next sibling pointer to avoid dangling pointers
node *next = child->nextSibling;
free_tree_helper(child);
child = next;
}
// All the children have been freed, now free the parent
free(n->name);
free(n->text);
free(n);
}
Alternatively, if you use a memory pool to allocate your tree nodes, all of your nodes come from the same pool, and the pool contains no other tree's nodes, you can instead just free the entire memory pool at once, saving you from having to traverse the entire tree. This will be much more efficient, since it avoids a lot of cache misses in a potentially large tree, and it also avoids certain memory fragmentation problems.
Related
I want to build a graph that creates a new parent node by merging two child nodes. The code below is supposed to merge node a and b into a parent node c. Then, nodes a and c to create a parent node d:
a b
|---|
|
a c
|---|
|
d
When I try to free the graph starting at node d I get a segmentation fault and I don't know why. Somehow it works if I don't use the same node twice in the graph. However, I want to be able to use the same node more than once. Can someone please tell me what am I missing here?
#include <stdlib.h>
struct Node {
int data;
struct Node *child1;
struct Node *child2;
};
struct Node *NewNode(double data) {
struct Node *node = NULL;
node = malloc(sizeof(*node));
if (node == NULL) {
return node;
}
node->data = data;
node->child1 = NULL;
node->child2 = NULL;
return node;
}
struct Node* merge(struct Node *self, struct Node *other) {
struct Node *node = NewNode(-1);
node->child1 = self;
node->child2 = other;
return node;
}
void free_graph(struct Node **node) {
if (*node != NULL) {
free_graph(&(*node)->child1);
free_graph(&(*node)->child2);
free(*node);
*node = NULL;
}
}
int main(void){
struct Node *a = NewNode(1);
struct Node *b = NewNode(2);
struct Node *c = merge(a, b);
struct Node *d = merge(a, c);
free_graph(&d);
}
It does not work because your "tree" does not match your illustration, and is in fact technically not a tree. What you have looks like this:
You need to make a copy instead of reusing a node if you want a tree.
In order to free everything in a graph like this, I'd suggest having a separate linked list to keep track of everything you need to free.
If you don't want to do that, or cannot do that for some reason, it gets more complicated. Performing an operation an all nodes in a tree is trivial, but for a general directed graph it's slightly more complicated. I guess this answer could help, and if not, it at least gives you an idea about what to search for:
Finding list of all nodes in a directed graph
I assume you could do something like this pseudo:
getAllNodes(root, nodes)
if root // NULL check
if not node in nodes // If it's the first time we visit the node
// Add this node to the list of visited nodes
nodes = nodes + [root]
// And then call this function recursively on the children
getAllNodes(root->left, nodes)
getAlLNodes(root->right, nodes)
nodes = []
getAllNodes(root, nodes)
for node in nodes
free(node)
Trees have the nice feature that they never contain loops. But directed graphs do, so you have to have some check to see if a node is already visited. Note that in order for this to work, it has to be called from the root. Or to be more precise, every node needs to be reachable from the node. But that's not so different from a tree.
I guess you could somehow move the free inside to create a freeAllNodes() function, but this is more flexible. Maybe you want a list for other purposes. So my suggestion in that case is to just make freeAllNodes() call getAllNodes().
I could write an implementation for the above, but since C does not provide library functions for linked lists, that would mean including a lot of extra code.
You put a into the intended tree twice, so free_graph attempts to free it twice. Calling free twice on the same address from the same original allocation is improper.
If you want to have a true tree, do not put any node into it twice. If you want to have a data structure that can have the same node in it twice, either use separate copies of the node (e.g., two different allocations for struct Node with the same value for data) or make provisions in the data structure to avoid freeing it twice (for example, add a reference count to struct node to count how many times it is currently in the tree, and free the node only when its reference count reaches zero).
I have a dynamic data structure which looks like this:
struct tree_node {
int y;
int x;
struct tree_node *left;
struct tree_node *right;
struct tree_node *parent;
};
The structure is a node of a binary tree, with the addition that each node also points to its parent. Now, using the classical method of adding nodes to the binary tree using malloc() I can populate the binary tree easily. However, I am having trouble deallocating the binary tree from memory.
Usually, to remove nodes from the binary tree you perform a post-order traversal and then free each node like this:
void deleteTree(struct tree_node* node)
{
if (node == NULL) return;
deleteTree(node->left);
deleteTree(node->right);
printf("Deleting node with values [%d][%d]\n", node->y , node-> x);
free(node -> left);
free(node -> right);
free(node -> parent);
free(node);
printf("\nNode deleted");
}
However, when I run the above function it does not deallocate the binary tree from memory. When I run the function, it deallocates one leaf and then when it tries to delete the next node it gets stuck in an endless loop and my computer either crashes or the program exits with a non-descriptive error.
The output in the terminal is the following:
Deleting node with values [11][4]
Node deleted
Deleting node with values [7739840][0]
So the terminal shows that it deletes the first leaf, and then it tries to fetch the values from the next node but it cannot (which is why it displays 7739840). Then it gets stuck in an endless loop since it does not print "Node deleted".
How can I correctly deallocate the memory? Does it have to do with the way my node is built?
The correct way of deallocating all the nodes from your tree structure looks like this:
void deleteTree(struct tree_node* node)
{
if (node == NULL) return;
deleteTree(node->left);
deleteTree(node->right);
free(node);
}
You're deallocating nodes multiple times.
When you delete a given node, after deleteTree(node->left) is called the left node has already been freed, so it doesn't need to be freed again. So remove free(node->left).
The current node has also been freed because free(node->parent) was called in that function, so any further reads of node access freed memory. So remove free(node->parent).
And similarly to the call to deleteTree(node->left), calling deleteTree(node->right) already frees the right node, so remove the call to free(node->right).
So now you're left with:
void deleteTree(struct tree_node* node)
{
if (node == NULL) return;
deleteTree(node->left);
deleteTree(node->right);
printf("Deleting node with values [%d][%d]\n", node->y , node-> x);
free(node);
printf("\nNode deleted");
}
In short, each node is responsible for cleaning itself up.
This is happening because you are freeing the same node multiple times.
To delete a binary search tree you have to do something like this.
void bst_destroy(BSTNode node) {
if (node == NULL) {
return;
}
bst_destroy(node->left);
bst_destroy(node->right);
free(node);
}
Basically to delete a binary search tree you have to delete the leaves of the tree one by one so you don't end up deleting parent nodes you might have to visit again (which you will have to do if you are using recursion).
I have a function that creates a binary tree, and for each node in the tree, I need to add a node to a separate linked list that points to the node in the binary tree.
My function to create the binary tree:
typedef struct myTree _node;
void INSERT(_node *(*tree), _node *item) {
if (!(*tree)) {
*tree = item;
return;
}
if (item->val < (*tree)->val) {
INSERT(&(*tree)->left, item);
}
else if (item->val > (*tree)->val) {
INSERT(&(*tree)->right);
}
}
My main function:
int main(void) {
int i;
int *balanced;
_node *current, *root;
root = NULL;
for (i = 0; i < size; i++) {
current = (_node *)malloc(sizeof(_node));
current->left = current->right = NULL;
current->val = balanced[i];
INSERT(&root, current);
}
return 0;
}
I've left out parts of my main function for simplicity.
The idea is that I want to print out the contents of the tree in pre, in, and post order, as well as traverse the linked list and print the value of the node in the tree that each linked list node points to.
I'm only a few months into learning C, so I am not terribly advanced.
Much like your insert function is recursive on the tree, walking the tree is recursive as well. There are two ways to do this: the specific way and the generic way. Let's see both.
The specific way just prints values as it encounters them. It solves this specific problem: printing the values. If you have to do tree walks to do more than one thing, you'd have to copy the code, which is generally a bad thing.
On the other hand, the code is much simpler and easier to follow. Let's look at the in-order case (you can do the other two by yourself; they are very similar):
void print_in_order (const struct myTree * tree) {
// if we're in a null node, do nothing
if (!tree) return;
// otherwise, do the left subtree, then the current node, then the right subtree
// non-existent subtrees will be handled by the above check, so don't check twice
print_in_order(tree -> left);
printf("%d\n", tree -> val);
print_in_order(tree -> right);
}
The generic way, on the other hand, is a better approach if your program is doing tree walks for all sorts of purposes. The idea is that you encapsulate the actual task to be done at each node (in this case, printing it) in a separate function:
void print_node (const struct myTree * node) {
printf("%d\n", node -> val);
}
And then you write a function that takes this function as an argument and calls it on each node, in the corresponding order. Let's do it for in-order:
void apply_in_order (const struct myTree * tree,
void (* callback)(const struct myTree *)) {
// this is the same as before...
if (!tree) return;
apply_in_order(tree -> left, callback);
// ...except that, instead of doing a specific thing, we call the callback on each node
callback(tree);
apply_in_order(tree -> right, callback);
}
Now, you just call this function as apply_in_order(tree, print_node); and you get the same behavior as above. But the next time you need to write a function that walks a tree, you only need the per-node thing; the rest is already done.
I am using the following free function for my tree:
void freeTree(struct node *tree) {
if (tree == NULL) return;
freeTree(tree->left);
freeTree(tree->right);
free(tree);
}
And I am creating a tree/operating on it like this:
struct node *root = NULL;
root = createTree(testNodes);
inOrderPrint(root);
freeTree(root);
Definition of node struct:
struct node {
int val;
int color;
struct node *parent;
struct node *left;
struct node *right;
};
I have noticed after running this enough (many hours), memory starts to build up (very little amount) in my IDE (I am using CLion). I am posting to ask if my freeTree function is implemented correctly to rule that out and to see if it could be something else causing this slow memory build up.
Supposing that your tree is in fact constructed in the manner implied by the names of the members of struct node, and that nodes' left and right pointers are set to NULL for nodes that do not have a left or right child, respectively, your freeTree() function will free all memory associated with the (sub) tree whose root node its argument points to. If you have a leak, it is elsewhere.
I have a n-ary tree structure with only parents and children. The spantree itself holds only one node, the root. Then there are created nodes which are linked with other nodes or the root. Each node(root included) are allowed to have up to MAXCHILDREN children nodes.
Here's the structure:
typedef struct node{
unsigned int id; //every node has different id
struct node* parent; //points to parent node
struct node* children[MAXCHILDREN]; //pointers to all children of this node
}node;
typedef struct spantree{
node root; //root node
}spantree;
Visual picture:
root
___O
/ / \
O O O
/ \
O O
After I have created my tree I want to deallocate the whole thing but I am unsure on which way to do it. I can't start deallocating from the root because then the tree will get broken. So I imagine that I have to start from the leaves and going up to the root?
But that means that I have to find the deepest leaves first, right? I feel quite confused on how to start.
I don't think it's neccesary but for insurance here's what I use everytime I need to make a new node:
node *newNode;
newNode=(node*)malloc(sizeof(node));
//then I modify it to my preferences
You need to check if the node you're freeing has children, and free them first if it does.
void free_node( node *n ) {
if(n) {
for(int i=0; i<MAXCHILDREN; i++)
free_node(n->children[i]);
free(n);
}
}
Recurse through the tree, call the recursive function first, then free memory.
void deleteNode(node * Node) {
for (int i = 0; i < MAXCHILDREN; ++i) {
if (node->children[i]) {
deleteNode(node->children[i]);
free(node->children[i]);
}
}
}
You're correct, you need to use your favorite traversal function to find the leaves, and then free those before freeing the parent nodes. Once the children have been freed, you basically have another leaf node that you can then free.
You'll need to use recursion. Enjoy!
You heard anything about POST-ORDER Traversing? You use the same technique to delete all of the nodes. This automatically deletes the parents after all their children are deleted.