Binary Tree Extraction code - c

I have pre-written code that I'm trying to wrap my head around:
int maxExtract(node **tree)
{
node *prev = NULL;
node *curr = *tree;
int ret;
if(curr == NULL)
{
printf("Tree is empty!\n");
exit(-1);
}
while( curr->right != NULL )
{
prev = curr;
curr = curr->right;
}
ret = curr->data;
if( prev != NULL )
prev->right = curr->left;
else if( curr == *tree )
*tree = curr->left;
free(curr);
return ret;
}
I understand everything except the else if (curr == *tree) condition. I think it's saying that if the max node ends up being the root. However, wouldn't you need to change more connections than that after the else if, like to connect the right and left side of the tree to this new root after extracting the old one?

I think it's saying that if the max node ends up being the root.
That is exactly what it means and, if that's the case, then there can be nothing in the right side of that node because, if there were, the maximum would be somewhere in that (right) sub-tree, not at the root.
So let's consider the tree where the root is the maximum (and A1/A2 are arbitrary sub-trees, including empty ones):
MAX
/
x
/ \
A1 A2
To extract the maximum value, what you want to be left with is simply:
x
/ \
A1 A2
So the operation you want to perform is to make x the new root of the tree - this is done with the line in your code:
*tree = curr->left;
I'd probably write it slightly differently to explicitly handle the disparate cases rather than relying on things happening or not happening depending on various decisions in the middle of the code. By that, I mean:
int maxExtract (node **tree) {
// Handle empty tree as error.
if (*tree == NULL) {
printf ("Tree is empty!\n");
exit (-1);
}
// Handle root is max, i.e., has no right subtree.
if ((*tree)->right == NULL) {
node *nodeToDelete = *tree; // Save root for deletion.
int retVal = nodeToDelete->data; // Get data to return.
*tree = nodeToDelete->left; // Set new root.
free (nodeToDelete); // Delete old root.
return retVal; // Return old root value.
}
// Locate max and its previous.
node *prev = *tree;
node *curr = (*tree)->right;
while (curr->right != NULL) {
prev = curr;
curr = curr->right;
}
// Max has no right sub-tree but it MAY have a left one
// which needs to be transferred as-is to the right of prev.
int retVal = curr->data; // Get data to return.
node *nodeToDelete = curr; // Save root for deletion.
prev->right = curr->left; // Transfer left sub-tree (or null).
free (nodeToDelete); // Delete old max.
return retVal; // Return old max value.

Related

Trying to change a maze pathfinder algorithm from using DFS to BFS to find the shortest path in C

I have created a pathfinding algorithm in C that uses a map.txt file with a maze written in 0s for walls and 1s for paths. Currently the path finding algorithm I'm using is a DFS with a stack to keep track of nodes but I'm trying to change it to a queue to utilize BFS so that I will be certain that the shortest path is always found. But when I try to print out the new path in BFS it seems like the rest of the path gets deleted somewhere but I can't find where.
Here is the path-finding algorithm in question:
struct node *BFS(struct graph* graph, int vertex, int endVertex, struct node* path_stack) {
struct node* temp = graph->adjlist[vertex]; //This is the first neighbor to the vertex node
struct node* temp2 = graph->adjlist[endVertex];// We use this temp to check if there exist a path at all (if the end node exist and has neighbours)
graph->visited[vertex] = 1; // sets the self as visited
static int done = 0;
if(temp2 == NULL || temp == NULL)
{
printf("No Path can be found");
return path_stack;
}
// if we havent arrived yet
while (temp != NULL) { // checks if the current neighbor exists
if(done == 1)
{
break;
return path_stack;
}
if(temp->vertex == endVertex) // Check for when we have gotten to the goal
{
printStack(path_stack);
done = 1;
break;
}
path_stack = push(temp, path_stack); // we push the first neighbor to the stack
if (graph->visited[temp->vertex] == 0) { //if the neighbor is not visited we run the algorithm again and now with the neighbors value as the vertex
BFS(graph, temp->vertex, endVertex,path_stack);
}
else
{
if(graph->visited[temp->vertex] == 1)
{
path_stack = pop(path_stack);
}
temp = temp->next; // we go the next neighbor to the current node
}
}
return path_stack;
}
Here is my push code that has been changed to push last like a queue:
struct node* push(struct node* Node, struct node* head)// Push has now been altered to push like a queue, so we can use bfs instead of dfs
{
struct node* temp = CreateNode(Node->vertex,Node->Y,Node->X); // We use a queue to keep track of visited nodes
temp->next = NULL;
if(head == NULL)
head = temp;
else
{
head->next = temp;
head = temp;
}
return head;
}
and here is my function that prints the path but now it only prints the last node in the path and all the others are gone.
void printStack(struct node* head)//Function that prints all the nodes in the stack
{
struct node* tmp = head;
//struct node* tmp2 = NULL;
printf("(The Start)->");
while(tmp != NULL)
{
//tmp2 = push_path(tmp, tmp2);
printf("(%d,%d)->", tmp->X, tmp->Y);
tmp = tmp->next;
}
/* while(tmp2 != NULL)
{
printf("(%d,%d)->", tmp2->X, tmp2->Y);
tmp2 = tmp2->next;
}
*/
printf("(The End)\n");
}
The code for printing the path has also been changed a little because when using DFS the path would be printed reversed so the code that has been commented out was for when I needed to reverse it back but now it's not necessary to use it. Any help with why the path can't be printed is very much appreciated, I'm still quite new to C programming and path finding algorithms.

Binary Tree Insert without ordering

Is there any way to insert a new node in a binary tree (not bst) without comparing key values? The following code only works for the very first three nodes.
node *insert (node *root, int *key) {
if (root==NULL) {
root=newNode(root, key);
return root;
}
else if (root->left == NULL)
root->left=insert(root->left,key);
else if (root-> right == NULL)
root->right=insert(root->right,key);
return root;
}
If you change
else if (root-> right == NULL)
to just
else
Then it would have the effect of always adding to the right.
If you want it to randomly pick, add a call to srand outside this function.
srand(time(NULL));
Then in this function, call
else if (rand() > MAX_RAND / 2) {
root->right = insert(root->right, key);
} else {
root->left = insert(root->left, key);
}
at the end of your existing if/else structure.
See also:
Lack of randomness in C rand()
If your tree tracks its height at each node, you could add after your null checks something like
else if (root->left->height <= root->right->height) {
root->left = insert(root->left, key);
} else {
root->right = insert(root->right, key);
}
That would keep the tree balanced automatically. But it requires additional code to manage the height. E.g.
root->height = 1 + ((root->left->height > root->right->height) ? root->left->height : root->right->height);
I leave it up to you whether that additional overhead is worth it.
The people suggesting using a heap are suggesting using the indexes as the ordering. This is kind of useless as a heap, but it would make a balanced binary tree. So the root node would be the first inserted and the most recent inserted would be the rightmost leaf.
You could just keep track of the height of each node, and always insert it into the side with fewer children:
node *insert (node *root, int *key) {
if (root==NULL) {
root=newNode(root, key);
root->height = 0
}
else if (root->left == NULL) {
insert(root->left,key);
}
else if (root->right == NULL) {
insert(root->right,key);
}
else if (root->left->height <= root->right->height) {
insert(root->left,key);
} else {
insert(root->right,key);
}
root->height++
}
Comparing values is actually irrelevant, the only think you need to do is set a pointer. Since you didn't specify any real requirements, one solution could be as follows:
Changing the signature a bit so now you have a pointer to an already allocated node:
void insertNode(node *&root, node *newNode) {
if (root == NULL) {
root = newNode;
return;
}
if (root->left == NULL) {
root-left = newNode;
return;
}
helperInsert(root->left, newNode);
return;
}
This will set the head (assuming I got the signature right), and otherwise check the left child.
void helperInsert(node *it, node *newNode) {
if (it->left == NULL) {
it->left = newNode;
return;
}
helperInsert(it->left, newNode);
return;
}
This is obviously a flawed approach (the tree will not be balanced at the slightest), almost treating the tree as a linked list, but to my best understanding of the question, this is an example of how it can be done.
In
else if (root->left == NULL)
root->left=insert(root->left,key);
you know root->left is NULL so why to do the recursive call ?
Of course same for the next else
The following code only works for the very first three nodes.
If both left and right are non NULL you do not insert, that time it was necessary to do the recursive call on one of the two branches, and you will consider the key (so insert ordered) to decide which one. Note that the 2 tests to NULL you did are not correct if you insert to have a sorted tree ...
The heap advice is most sound. You don't need to heapify anything, just follow the rules that an element at index k has children at 2*k + 1 and 2*k + 2.
Another approach, useful when there is no array, but the nodes are generated on the fly, is to fill the tree level-wise. Notice that at level k there are 2 ** k slots, conveniently indexed by a k-bit integer. Interpret the index as a path down the tree (clear bit tells to follow left child, set bit tells to follow a right one), along the lines of:
void insert_node(struct node * root, struct node * node, unsigned mask, unsigned path)
{
while ((mask >> 1) != 1) {
root = mask & path? root->right: root->left;
}
if (mask & path) {
assert (root->right == NULL);
root->right = node;
} else {
assert (root->left == NULL);
root->left = node;
}
}
void fill_level_k(struct node * root, unsigned k)
{
unsigned slots = 1 << k;
for (unsigned slot = 0; slot < slots; slot++) {
struct node * node = generate_new_node();
insert_node(root, node, slots, slot);
}
}

Deleting a node from a Binary Tree Search

I think there are multiple errors in my code for deleting a node from a BST. I just can't figure out what! Here's my code. Thanks in advance!
void del(int val){
help = root;
f = help;
while (help){
if(help->data==val) break;
f = help;
if (val > help-> data) help = help->right;
else help = help->left;
} if(help->data != val) printf("\nElement not found!");
else{
printf("Element found!");
target = help;
if(val>f->data){
if(target->right && !target->left) {f->right = target->right; f = target->right;}
else {f->right = target->left; f = target->left;}
} else{
if(target->right && !target->left) {f->left = target->right; f = target->right;}
else {f->left = target->left; f = target->left;}
}
while(help ->right) help = help->right;
if(help->left) help = help->left;
f->right = help;
free(target);
}
}
One error that I spot is that if one were to delete the left node in the tree, then the last few lines might not work since they are not symmetric. So, let us say, the tree has root as 6 and left-child as 4 and right-child as 8. Now, you want to delete 4. So, after you have found the node in the first while clause, you would hit the else clause of "if (val > f->data){". At this point, f would point to 6, target and help would point to 4. Now, you are setting the left of f to right of target, so left of 6 would point to NULL and f itself would point to NULL. So, far so good! But, once you get into the while loop, since help has no right node, help would continue to point to 6. In the end, you make the right node of f (btw, f is already NULL at this point) to help and you would actually end up crashing!
while (help->right)
help = help->right;
if (help->left)
help = help->left;
f->right = help;
Another error is that you do not update the root pointer, incase you end up deleting the root node.
One simpler approach would be to divide this into three cases. I am providing code for all the three cases. Use a sample tree for each of these three cases and then debug/test it.
First, if the found node (which your file while loop is doing) has no child nodes, then delete it and set its parent to NULL and you are done. Here is a rough-first cut of the first case:
/* If the node has no children */
if (!help->left && !help->right) {
printf("Deleting a leaf node \n");
f = help->parent;
if (f) {
if (value > f->value)
f->right = NULL;
else
f->left = NULL;
}
/* If deleting the root itself */
if (f->value == root) {
root = NULL;
}
free(help);
return 0;
}
Second, if the found node has only child (left or right), then splice it out and the child of the found node becomes hte child of the parent node. Here is the second case:
/* If the node has only one child node */
if ((help->left && !help->right)
|| (!help->left && help->right)) {
printf("Deleting a node with only one child \n");
f = help->parent;
if (help->left) {
child_node = help->left;
} else {
child_node = help->right;
}
if (f) {
if (value > f->value) {
f->right = child_node;
} else {
f->left = child_node;
}
} else {
/* This must be the root */
root = child_node;
}
free(help);
return 0;
}
The third case is tricky -- here the found node has two child nodes. In this case, you need to find the successor of the node and then replace the value of the found node with the successor node and then delete the successor node. Here is the third case:
/* If the node has both children */
if (help->left && help->right) {
successor_found = find_successor(help, help->data);
printf("Deleting a node with both children \n");
if (successor_found) {
successor_value = successor_found->value;
del(successor_found->value);
help->value = successor_value;
}
return 0;
}
And, here is the code to find successor:
binary_node_t *node find_successor(binary_node_t *node, int value) {
binary_node_t *node_found;
if (!node) {return NULL; }
node_found = node;
old_data = node->data;
/* If the node has a right sub-tree, get the min from the right sub-tree */
if (node->right != NULL) {
node = node->right;
while (node) {
node_found = node;
node = node->left;
}
return node_found;
}
/* If no right sub-tree, get the min from one of its ancestors */
while (node && node->data <= old_data) {
node = node->parent;
}
return (node);
}
typedef struct xxx {
struct xxx *left;
struct xxx *right;
int data;
} ;
#define NULL (void*)0
#define FREE(p) (void)(p)
void treeDeleteNode1 (struct xxx **tree, int data)
{
struct xxx *del,*sub;
/* Find the place where node should be */
for ( ; del = *tree; tree = (data < del->data) ? &del->left : &del->right ) {
if (del->data == data) break;
}
/* not found: nothing to do */
if ( !*tree) return;
/* When we get here, `*tree` points to the pointer that points to the node_to_be_deleted
** If any of its subtrees is NULL, the other will become the new root
** ,replacing the deleted node..
*/
if ( !del->left) { *tree = del->right; FREE(del); return; }
if ( !del->right) { *tree = del->left; FREE(del); return; }
/* Both subtrees non-empty:
** Pick one (the left) subchain , save it, and set it to NULL */
sub = del->left;
del->left = NULL;
/* Find leftmost subtree of right subtree of 'tree' */
for (tree = &del->right; *tree; tree = &(*tree)->left) {;}
/* and put the remainder there */
*tree = sub;
FREE(del);
}
To be called like:
...
struct xxx *root;
...
treeDeleteNode1( &root, 42);
...

How to delete all nodes of same value from linklist/Queue

I have been trying hard to resolve this however yet not succeed I have data structs as follow (which actually is very complex I just simplifies for discussion) :
typedef struct node{
struct node* next;
void* arg;
}node_t;
typedef struct queue{
node_t* head;
node_t* tail;
}queue_t;
addQ(queue_t*ptr , int data)
{
queue_t* q = ptr;
node_t * n = malloc(sizeof(*n));
n->arg = data;
n->next = NULL;
if(NULL == q->head){
q->head = q->tail = n;
return ;
}
q->tail->next = n;
q->tail = q->tail->next;
}
Now I want to delete node of same value ( I have tried couple ways however yet not succeed ) , Just consider this sequence for reference:
addQ(q, 12);
addQ(q, 12);
addQ(q, 4);
addQ(q, 12);
addQ(q, 12);
addQ(q, 14);
addQ(q, 12);
addQ(q, 12);
I want to Delete all the nodes with value 12.
This solution got a bit hairy with the double pointers, but I still like it, as it doesn't have to special case what node (first vs the rest) is being checked. I tried to put enough comments in to describe what's going on, but it's still hard for even me to follow at first glance.
PSEUDOCODE..
Queue * q;
VALUE = 12;
// double pointer so we can treat the queue head and subsequent nodes the same.
// because they are both pointers to Node.
// Otherwise you'd have to have code that says if the one you're removing is the
// first element of the queue, adjust q->head, otherwise adjust node->next.
// This lets you not special case the deletion.
Node ** node_ptr = &(q->head)
while (*node_ptr != null) {
if ((**node_ptr).arg == VALUE) {
// store off the matching node to be freed because otherwise we'd orphan
// it when we move the thing pointing to it and we'd never be able to free it
Node * matched_node = *node_ptr;
// when we find a match, don't move where node_ptr points, just change the value it
// points to to skip the matched node and point to the one after it (or null)
*node_ptr = matched_node->next;
free(matched_node);
} else {
// otherwise, nothing was deleted, so skip over that node to the next one.
// remember, **node_ptr is a double dereference, so we're at the node
// now, so then we grab the address of the non-matching node's next value so it can be
// potentially changed in the next iteration
node_ptr = &((**node_ptr).next);
}
}
Assuming that you already have a function that obtains and removes the next item in the queue, let's call it getQ(q), then you could achieve your goal without even having to know the internals of the queue, by just using the operations you already have, e.g. something like (this won't work because arg is a void, but the logic should be clear):
node_t *n;
queue_t *q2 = initialiseQ();
while (n = getQ(q)) {
if (n->arg != 12) {
addQ(q2,n);
}
}
free(q);
q = q2;
Here's an inline solution that doesn't use double pointers. It has to treat the first element and subsequent elements differently since the pointer to adjust changes from the queue structure to the node structure.
Also, for subsequent nodes, you have to track the trailing node, since that's where you have to make the adjustment as you delete the matching node.
Queue * q;
VALUE = 12;
// handle the case where the first node matches.
// you have to adjust the q's head pointer
// delete from the head and set a new head node until a non-matching head is found
while (q->head != NULL && q->head->arg == VALUE) {
Node * matching_node = q->head;
q->head = q->head->next;
free(matching_node);
}
// if there is more than one node left, need to check the subsequent nodes
if (q->head != NULL && q->head->next != NULL) {
Node * node_ptr = q->head->next;
Node * prev_node_ptr = q->head;
while (node_ptr != NULL) {
if (node_ptr->arg == VALUE) {
Node * matched_node = node_ptr; // don't orphan it before it's freed
// You don't move the prev_node pointer since that doesn't change when a match
// is found. Only the node_ptr, which skips to the next one.
node_ptr = node_ptr->next;
free(matched_node);
} else {
prev_node_ptr = node_ptr;
node_ptr = node_ptr->next;
}
}
}

Linkedlist not looping properly

I have a linked list of particles. I would like to make these particles move one-by-one. So in order to do that I need to loop through every particle in my linked list, and when it reaches the last particle, I would like it to go back to the first particle. but my program is not doing that.
int particle_update(struct particle **head ){
struct particle *current = *head;
struct particle *next;
printf("particle_update\n");
while(current != NULL){
while(current != NULL && current->lifespan >=0){
current->lifespan --;
current->pos.y = current->pos.y + (current->spd.y * current->dir.y);
current->pos.x = current->pos.x + (current->spd.x * current->dir.x);
current->pos.z = current->pos.z + (current->spd.z * current->dir.z);
current = current->next;
if (current == NULL)
current = *head;
}
}
particle_destroy(head);
return 0;
}
I got a feeling there's a number of problems....
one.... this is strange...
while(current->lifespan >= 0 && current != NULL){
it should be while(current != NULL && current->lifespan >= 0){
this means it will check its not null first, and only if it is not null, it will try and see what current->lifespan is. The way you have it, it will likely crash
also, I'm not sure if you want to move to the next as the first thing? I think it might be the last thing you want to do inthe loop
also, the outer loop will loop forever once you get the inner loop doing what you want.
I suspect what is going on here is that to destroy the particle you need to modify the particle before it, and improper handling of this case is what is tripping you up.
First, as soon as you hit the last node in your linked list, you call current = current -> next at the beginning of your while loop whereas you should be calling it at the end.
As a result, current is now null so you are going to hit BAD_EXEC errors when you call current->position as you are de-referencing a null pointer. Instead, increment current at the end of the while loop so that you never de-reference a null pointer.
Next, pointing current to head means that you never get to exit your loop except via particles expiring, which I assume is not what you want (otherwise you would have a while(1)).
So here is a better alternative for handling the surgery:
int particle_update(struct particle **head ){
struct particle * current = *head;
struct particle * prev = NULL;
while (current != NULL) {
// lifespan check
current->lifespan = (current -> lifespan > 0) ? current->lifespan-1:particle_destroy(&prev, &current);
// update position of current
...
// increment counter at end of while loop
prev = current;
current = current -> next; //now current is always one node ahead of previous.
}
return 0;
}
Then, your particle destroy function would be:
void particle_destroy(struct particle ** prev, struct particle ** current) {
if (*current = NULL) return; //nothing to do
struct particle * tmp = *current;
if (*prev != NULL) { /* need to modify previous node */
(*prev) -> next = current -> next;
} else { /* head has expired, so change head ptr to next node */
(*current) = (*current) -> next;
}
/* free resources */
// do other clean-up, if necessary.
free(tmp);
return;
}

Resources