Binary Trees - difference between insert and mirror? - c

What manipulations are we doing in insert/delete that we aren't in mirror?
By mirror I'm referring to switching the left and right child of every single node in the tree.
The reason I'm asking is that when it comes to an insert, if you don't save the root returned by the function, it leads to errors. The same is not true of mirror. I assumed mirror would have the same requirement (returning the root node), but that is not the case. Why is that?
Here's my code if it's relevant (the insert is implemented for a BST):
Insert:
Node *insert(Node *root,int val)
{
Node *newNode=NULL;
if(root==NULL)
{
newNode=(Node*) malloc(sizeof(Node));
newNode->value=val;
newNode->left=NULL;
newNode->right=NULL;
return newNode;
}
if(root->value>val)
{
root->left=insert(root->left,val);
}
else
{
root->right=insert(root->right,val);
}
return root;
}
Mirror:
void mirror(Node *root)
{
Node *temp_left;
if(root==NULL)
return;
temp_left=root->left;
root->left=root->right;
root->right=temp_left;
mirror(root->left);
mirror(root->right);
}

Notice the line:
root->left=insert(root->left,val);
Here you are assigning the result of insert() to root->left. You need insert() to return a node* pointer here, or else we would have no idea where malloc placed the new node in memory, and so you wouldn't be able to add the node to the tree.
On the other hand, mirror only traverses the tree recursively and swaps some already-existing pointers. You need never assign the result mirror() to a variable.

Related

How to correctly deallocate structure from memory

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

Why are the changes made to single pointer persists even after the function returns

I was reading the following article.
Add greater values of every node
So my doubt after the function void modifyBSTUtil(struct node *root, int *sum)
returns , why the changes made by it persist in the tree.
1.We are not using double pointers
2.Nor is the root global
3.We are not returning the address
Can anyone explain why this happens??
Code
void modifyBSTUtil(struct node *root, int *sum)
{
// Base Case
if (root == NULL) return;
// Recur for right subtree
modifyBSTUtil(root->right, sum);
// Now *sum has sum of nodes in right subtree, add
// root->data to sum and update root->data
*sum = *sum + root->data;
root->data = *sum;
// Recur for left subtree
modifyBSTUtil(root->left, sum);
}
Call : modifyBSTUtil(root, &sum)
Insert Function
struct node* insert(struct node* node, int data)
{
/* If the tree is empty, return a new node */
if (node == NULL) return newNode(data);
/* Otherwise, recur down the tree */
if (data <= node->data)
node->left = insert(node->left, data);
else
node->right = insert(node->right, data);
/* return the (unchanged) node pointer */
return node;
}
We need to return the address in case of insert function to make changes permanent and why not return here??
This works because in this example the linking between the nodes is not changed. Only the values they store (->data).
There's nothing sacred in a function that prevents is from making a persistent effect on the outside world, the only restriction is the arguments it receives may limit what data it may access.
In this case, it's getting a pointer to a node, and uses it to access the node and change the data there. It's not changing the pointer itself since that is given by value (i.e. - the pointer value is copied, so changing it won't be visible outside), but the pointer value is enough to access the memory of that node and change the values stored there.
Note that accessing the node itself can allow you to change the pointers there, and therefore change the tree structure anywhere below that node.

deletion of binary tree using new method

Actually I was stuck while implementing the deletion of a tree . I deleted the leaf nodes using free() and now the parent would become leaf nodes , and delete those nodes too using recursion . But the problem is leaf node is not getting deleted actually , its still there . And also the method i followed in deletion of tree is as follows
void deleteTree(struct node *root)
{
if(root->left == NULL && root->right == NULL)
{
free(root);
}
else
{
if(root->left != NULL)
deleteTree(root->left);
if(root->right != NULL)
deleteTree(root->right);
}
}
This method deleted only the leaf nodes , and the corresponding parent nodes were not deleted . After debugging in XCode I found out that the leaf nodes were not deleted , They were still there.
So, why this happening ?
void deleteTree(struct node *root)
{
if (root) {
deleteTree(root->left);
deleteTree(root->right);
free(root);
}
}
Your deleteTree() is not good for delete nodes in tree. What you are doing is preorder traverse in binary tree recursively. The node you delete/free from tree will be refereed again when function returns, and hence you are accessing a free node that will cause Undefined behavior at run-time.
Do not access freed memory:
According to the C Standard, the behavior of a program that uses the value of a pointer that refers to space deallocated by a call to the free() or realloc() function is undefined.
You should choose Post-order to free tree's node. because in post-order traversal you don't access a node that is processed (deleted/free). And your deleteTree() function should be something like as follows:
void deleteTree(struct node *root){
if(root == NULL) return;
deleteTree(root->left);
deleteTree(root->right);
free(root); // node processed and return
}
Since you do not free the parent nodes on any level, all levels except for leaves remain. What you need to do is add free(root) after the if statement, at the end of the else statement.

Pointers in c: Function which deletes every second element of linked list

I want to write a function which gets a pointer to a header of a linked list and deletes from the list every second member of it. The List is a linked elements of type element:
typedef struct element{
int num;
struct element* next;
}element;
I'm new to all these pointers arithmetic so I'm not sure I write it correctly:
void deletdscnds(element* head) {
element* curr;
head=head->next; //Skipping the dummy head//
while (head!=NULL) {
if (head->next==NULL)
return;
else {
curr=head;
head=head->next->next; //worst case I'll reach NULL and not a next of a null//
curr->next=head;
}
}
}
I kept changing it since I kept finding errors. Can you please point out any possible errors?
The algorithm is a lot simpler if you think of your linked list in terms of node pairs. Each iteration of your loop should process two nodes - head and head->next, and leave head equal to head->next->next upon exit. It is also important to not forget deleting the middle node, if you are cutting it out of the list, otherwise you are going to see memory leaks.
while (head && head->next) {
// Store a pointer to the item we're about to cut out
element *tmp = head->next;
// Skip the item we're cutting out
head->next = head->next->next;
// Prepare the head for the next iteration
head = head->next;
// Free the item that's no longer in the list
free(tmp);
}
It might be most straightforward to visualize this problem in recursive terms, like this:
// outside code calls this function; the other functions are considered private
void deletdscnds(element* head) {
delete_odd(head);
}
// for odd-numbered nodes; this won't delete the current node
void delete_odd(element* node) {
if (node == NULL)
return; // stop at the end of the list
// point this node to the node two after, if such a node exists
node->next = delete_even(node->next);
}
// for even-numbered nodes; this WILL delete the current node
void delete_even(element* node) {
if (node == NULL)
return NULL; // stop at the end of the list
// get the next node before you free the current one, so you avoid
// accessing memory that has already been freed
element* next = node->next;
// free the current node, that it's not needed anymore
free(node);
// repeat the process beginning with the next node
delete_odd(next);
// since the current node is now deleted, the previous node needs
// to know what the next node is so it can link up with it
return next;
}
For me, at least, this helps clarify what needs to be done at each step.
I wouldn't advise actually using this method because, in C, recursive algorithms may take up a lot of RAM and cause stack overflows with compilers that don't optimize them. Rather, dasblinkenlight's answer has the code that you should actually use.

Convert recursive binary tree traversal to iterative

I was asked to write the iterative version, but I wrote the recursive version i.e.
void inorderTraverse(BinaryTree root)
{
if(root==NULL)
printf("%d",root->id);
else
{
inorderTraverse(root->left);
printf("%d",root->id);
inorderTraverse(root->right);
}
}
I'm not looking for the code, I want to understand how this can be done. Had it been just the last recursive call, I would have done
void inorderTraverse(BinaryTree root)
{
while(root!=NULL)
{
printf("%d",root->id);
root=root->right;
}
}
But how do I convert to an iterative program when there are two recursive calls?
Here are the type definitions.
struct element{
struct element* parent;
int id;
char* name;
struct element* left;
struct element* right;
};
typedef element* BinaryTree;
This is what I thought of, am I on the right track?
temp=root;
while(1)
{
while(temp!=NULL)
{
push(s,temp);
temp=temp->left;
continue;
}
temp=pop(s);
if(temp==NULL)
return;
printf("%d\t",temp->data);
temp=temp->right;
}
The problem you're seeing is that you need to "remember" the last place you were iterating at.
When doing recursion, the program internally uses "the stack" to remember where to go back to.
But when doing iteration, it doesn't.
Although... does that give you an idea?
I can't think of a really elegant way to do this iteratively off-hand.
One possibility might be using a 'mark algorithm', where you start out with all nodes 'unmarked' and 'mark' nodes as they're handled. The markers can be added to the object model or kept in a seperate entity.
Pseudocode:
for (BinaryTree currentNode = leftmostNode(root); currentNode != null; currentNode = nextNode(currentNode)):
print currentNode;
currentNode.seen = true;
sub nextNode(BinaryTree node):
if (!node.left.seen):
return leftmostNode(node.left)
else if (!node.seen)
return node
else if (!node.right.seen)
return leftmostNode(node.right)
else
return nextUnseenParent(node)
sub leftmostNode(BinaryTree node):
while (node.left != null)
node = node.left
return node;
sub nextUnseenParent(BinaryTree node):
while (node.parent.seen)
node = node.parent
return node.parent
I take it for granted, that iterating down from the parent nodes to the left nodes is not a problem. The problem is to know what to do when going up from one node to the parent: should you take the right child node or should you go up one more parent?
The following trick will help you:
Before going upwards remember the current node. Then go upwards. Now you can compare: Have you been in the left node: Then take the right node. Otherwise go up one more parent node.
You need only one reference/pointer for this.
There is a general way of converting recursive traversal to iterator by using a lazy iterator which concatenates multiple iterator suppliers (lambda expression which returns an iterator). See my Converting Recursive Traversal to Iterator.

Resources