C: How deallocate memory for spanning tree? - c

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.

Related

Freeing dynamically allocated graph nodes in C

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

Adding a new branch to a tree then adding the new leaf to the right place in a linked list in an efficient way

Suppose we have a binary tree and a linked list that holds the data that appears in all of the leafs.
For example, the following tree's list would be: 9,2,3 (order matter, left to right)
Now we add a new node somewhere, thus creating a new branch, like so:
Is there an efficient way to add this new leaf to list such that the list will keep the order of the leafs from left to right? i.e the new list is supposed to be 9,1,2,3.
Anything I come up with, in the worst case scenario, is the same as making a completely new list, i.e, traversing the whole tree.
Like traversing the tree in LDR and looking for the new leaf while keeping the info of the last leaf, but it could go through all or most of the tree in the worst case scenario.
BTW the list and tree are arbitrarily defined like so:
typedef struct listNode {
int data;
struct listNode* next;
} ListNode;
typedef struct treeNode {
int data;
struct treeNode* parent; //prev node
struct treeNode* left;
struct treeNode* right;
} TreeNode;
Yes there is, but it will also require adding some more data to treeNode, a pointer to the list node (if such exist).
Now, the idea is once you have found where to add the new node (v), and let's say it is a son of some node u.
You need to find the previous leaf. It can be done in O(h) by going up on the tree, until you have found a node x that has a left son. Go to the left son, and keep traversing on it, in the following order:
if the current node has right son:
go to right son, repeat
else if the current node has left son:
go to left son, repeat
else:
found previous leaf, let it be l
Now, you have the new node v, and the previous leaf l.
All you have to do now is to put v's node after l's node:
v.node = createNode();
v.node.next = l.node.next;
l.node.next = v.node;
Complexity of this algorithm is O(h), where h is the height of the tree.
Note: Take care of the simple edge case where v is the first node in the linked list.

Binary-like tree in C - recursion

Recursion is soo confusing for me...
below are the structs that are used to create the binary-like tree:
struct parent {
char *name;
Child *children;
};
typedef struct parent Parent;
struct child {
struct Parent *Pptr;
struct child *next;
};
typedef struct child Child;
I want to iterate through the entire tree and on each child/parent (basically every node) call a function called birthdaygift().
Below is what I've tried so far, but I don't think it works.
tree(Parent *parent) {
Child* child = parent->children;
birthdaygift(parent);
if (child == NULL) {
return;
}
while (child->next != NULL) {
Parent * recurseparent = child->Pptr;
tree(recurseparent);
}
birthdaygift(parent);
}
It'd be really helpful if someone can give me some pointers?
Your data structure looks very, very odd, it looks like you have the child nodes pointing back to the parents and are somehow maintaining the list of children in the child node as a linked list.... I'll give my answer assuming you are intending to work with a binary tree.
Now, assuming that is the case, wouldn't going up to the parent from one child and then going up from the next child take you to the same node? Typically, binary trees are parsed by starting from the top and going down.
A traditional binary tree has pointers from the parent (for this example, *left and *right), and you would traverse the entire tree by using either a Depth First Search algorithm (basically, you keep going left recursively until you run out of nodes, and then you go right), in pseudocode
function gift_node(*node) {
birthday_gift(node);
if (node->left != NULL) gift_node(node->left);
if (node->right != NULL) gift_node(node->right);
}
Now, if you were to watch the process parsing this binary tree, you would see it start at the top and keep following the left node. It would then backtrack, process the right node and it's subordinate nodes and keep going until it has visited every node.
The struct you declared is not a tree, it is similar to a doubly-linked list.
The struct for a binary tree node would be:
struct BST_Node {
Value value;
BST_Node *right;
BST_Node *left;
};
For traversing a tree, you want to visit every single node. One way to do this is to visit all the nodes to the left recursively, then the node itself, then all the nodes to the right recursively (this is known as in-order traversal, but this isn't important for this situation).
If you want to call birthdaygift() on each node:
void traverse(Node *n) {
if (n->left)
traverse(n->left);
birthdaygift(n);
if (n->right)
traverse(n->right);
}
A discussion of other tree traversal algorithms can be found here.

How to free tree effectively

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.

Iterating over AVL tree in O(1) space without recursion

I have an AVL Tree. Each node looks like this:
typedef struct {
Node *parent; // the parent node
Node *left; // the node left of this node
Node *right; // the node right of this node
int height; // the height of this node
void *value; // payload
} Node;
Is it possible to iterate over an AVL tree with these nodes in O(1) space, without recursion, if yes, how?
If not, a solution with sub-O(n) space or iff really necessary O(N) space is appreciated as well.
With iterating over the tree I mean I want to visit each node once, and if possible in order (from the mostleft to the mostright node).
If you store the last node you have visited, you can derive the next node to visit in an iterator.
If the last node was your parent, go down the left subtree.
If the last node was your left subtree, go down the right subtree.
If the last node was your right subtree, go to your parent.
This algorithm gives you a traversal in O(1) for the tree. You need to flesh it out a little for the leaves and decide what kind of iterator (pre/in/post-order) you want to decide where the iterator should and wait for incrementation.
It is possible to get the next in-order node given a pointer to some node, as long as you keep parent pointers. This can be used to iterate the tree, starting with the leftmost node. From my implementation of AVL tree:
BAVLNode * BAVL_GetNext (const BAVL *o, BAVLNode *n)
{
if (n->link[1]) {
n = n->link[1];
while (n->link[0]) {
n = n->link[0];
}
} else {
while (n->parent && n == n->parent->link[1]) {
n = n->parent;
}
n = n->parent;
}
return n;
}
To get the leftmost node:
BAVLNode * BAVL_GetFirst (const BAVL *o)
{
if (!o->root) {
return NULL;
}
BAVLNode *n = o->root;
while (n->link[0]) {
n = n->link[0];
}
return n;
}
Here, node->link[0] and node->link[1] are the left and right child of the node, respectively, and node->parent is the pointer to the parent node (or NULL for root).
A single GetNext() operation has O(logn) time complexity. However, when used to iterate the entire tree, you get O(n) amortized time complexity.
"Datastructures and their algorithms" by Harry Lewis and Larry Denenberg describe link inversion traversal for constant space traversal of a binary tree. For this you do not need parent pointer at each node. The traversal uses the existing pointers in the tree to store path for back tracking. 2-3 additional node references are needed. Plus a bit on each node to keep track of traversal direction (up or down) as we move down. In my implementation of this algorithms from the book, profiling shows that this traversal has far less memory / processor time. An implementation in java (c would be faster i guess) is here.

Resources