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.
Related
I am trying to create a function which returns the mirrored copy of a binary tree.
By "mirrored" I mean a tree with each left node as its right node and vice versa.
The one on the left gets copied to resemble the one on the right. This is the code of the function, with the definition of the binary nodes and "insert node" function that I use:
typedef struct bNode {
int data;
struct bNode *left;
struct bNode *right;
} bNode;
// =============================================================
bNode* reverse_tree (bNode **tree) {
bNode *copy = malloc(sizeof(bNode));
copy->data = (*tree)->data;
if (!((*tree)->right) && !((*tree)->left)){
return copy;
}
copy->left = reverse_tree(&(*tree)->right);
copy->right = reverse_tree(&(*tree)->left);
return copy;
}
// =============================================================
void insert(bNode **tree, int data) {
bNode *temp, *previous, *current;
if (*tree == NULL) {
temp = (bNode *) malloc(sizeof (bNode));
temp->data = data;
temp->left = NULL;
temp->right = NULL;
*tree = temp;
return;
}
if (data < (*tree)->data) {
insert(&(*tree)->left, data);
} else if (data > (*tree)->data) {
insert(&(*tree)->right, data);
}
}
After some troubleshooting, one single layer of recursion works fine, but after that, the pointers break (that is, they point to an inaccessible part of memory), and the program receives a SIGSEGV Segmentation fault.
Why do I receive this SIGSEGV and how do I avoid it?
P.S I am quite inexperienced with pointers; I hope it's not too bad.
(The one on the left gets copied to resemble the one on the right)
At least the function reverse_tree has a bug.
The sub-statement of this if statement:
if (!((*tree)->right) && !((*tree)->left)){
return copy;
}
gets the control when the both pointers, right and left, are null pointers.
So this code snippet:
copy->left = reverse_tree(&(*tree)->right);
copy->right = reverse_tree(&(*tree)->left);
can get the control when only one of the pointers is a null pointer.
In this case in the next recursive call of the function this statement:
copy->data = (*tree)->data;
invokes undefined behavior for the passed null pointer.
I am implementing the insert function of a binary search tree in C and I am encountering a problem with malloc.
First of all, I have a Tree and Node struct
typedef struct Node {
double value;
struct Node *parent;
struct Node *right_child;
struct Node *left_child;
} Node;
typedef struct Tree {
struct Node *root;
} Tree;
And here is my insert function to insert a value into the tree.
void insert(Tree *t, double v) {
Node *n = malloc(sizeof(Node));
n->left_child = malloc(sizeof(Node));
n->right_child = malloc(sizeof(Node));
n->parent = malloc(sizeof(Node));
n->value=v;
Node *x = t->root, *y = NULL;
//follow tree down until we reach a leaf of the tree
while (x) {
//save last non-NULL value. We will insert node n as a child to this leaf.
y = x;
if (n->value < x->value) {
x = x->left_child;
} else {
x = x->right_child;
}
}
//The parent of the node to insert is the leaf we reached
n->parent = y;
//If n is greater than y then it is its right child and vice-versa.
if (n->value > y->value) {
y->right_child = n;
} else {
y->left_child = n;
}
}
And my main method
int main(void) {
Node n1;
n1.value = 4;
n1.parent = NULL;
n1.left_child = NULL;
n1.right_child = NULL;
Tree t;
t.root = &n1;
insert(&t,2.0);
printf("In order traversal\n");
inOrderTraversalNode(t.root);
return EXIT_SUCCESS;
}
When I print the in-order traveral code I get undefined behavior (eg: 26815615859885194199148049996411692254958731641184786755447122887443528060147093953603748596333806855380063716372972101707507765623893139892867298012168192.000000) instead of the correct traversal.
I am pretty sure the problem is the Node creation in the insert method. I assume the problem is that the new node exists on the stack which is then being destroyed when the insert function exits - which is what is causing the undefined behaviour during the traversal. However, I thought that malloc stores the variable on the heap and makes it available globally. Or perhaps the node is on the heap but the pointer is on the stack? Could someone show me where I am going wrong here?
The initial contents in the memory allocated via malloc is undefined.
Firstly, remove n->parent = malloc(sizeof(Node));, which causes memory leak.
Secondly, change
n->left_child = malloc(sizeof(Node));
n->right_child = malloc(sizeof(Node));
to
n->left_child = NULL;
n->right_child = NULL;
so that the program can correctly recognize the leaf.
Try using calloc instead of malloc. The problem is that malloc doesn't initialize values to zero, it only allocates the space. calloc zeros out the space you're requesting. So, you're getting jumped to a random part of memory occasionally when you get to a pointer that isn't valid, but isn't NULL either.
malloc and friends definitely allocate on the heap, you've got that thinking right; what they return is a pointer to a space in memory of at least the size you requested that is definitely safe to read from and write to. However, since the value isn't zeroed out to begin with when you use malloc, you aren't able to guarantee that the pointer stored in your struct is actually to a valid location.
EDIT: also, other poster is right: there is definitely a memory leak with what you're doing. Didn't catch that.
This is homework for my first class in c. It focuses on dynamic allocation in c, in the form of a bst.
I have to have a dynamically allocated BST, recursively implemented. I know that my traversal works correctly, and am having trouble inserting nodes. I only ever have the root node, and every other node seems to be set to NULL. I think that I can't print the rest of the nodes when traversing, because I am trying to access the data member of a NULL struct. My code so far is as follows:
void insert_node(TreeNode** root, int toInsert){
if(*root==NULL){
TreeNode *newnode = (TreeNode *)malloc(sizeof(TreeNode));
newnode->data = toInsert;
newnode->left = NULL;
newnode->right = NULL;
}
else if(toInsert > (*root)->data){ //if toInsert greater than current
struct TreeNode **temp = (TreeNode **)malloc(sizeof(struct TreeNode*));
*temp = (*root)->right;
insert_node(temp, toInsert);
}
else{ //if toInsert is less than or equal to current
struct TreeNode **temp = (TreeNode **)malloc(sizeof(struct TreeNode*));
*temp = (*root)->left;
insert_node(temp, toInsert);
}
}
void build_tree(TreeNode** root, const int elements[], const int count){
if(count > 0){
TreeNode *newroot = (TreeNode *)malloc(sizeof(TreeNode));
newroot->data = elements[0];
newroot->left = NULL;
newroot->right = NULL;
*root = newroot;
for(int i = 1; i < count; i++){
insert_node(root, elements[i]);
}
}
I'm sure it's only one of many problems, but I get segmentation faults on any line that uses "(*root)->data", and I'm not sure why.
As a side note, despite getting segmentation faults for the "(*root)->data" lines, I'm still able to printf "(*root)->data". How is it possible to print the value, but still get a segmentation fault?
It's messy. Some things that might help
1) Don't need to use TreeNode*, pointer to pointer, as argument. Use jsut the TreeNode. (something went wrong here, as it's some feature from the text editor, consider and additional * after each TreeNode in this line)
2) Not a strict rule, but as best practice avoid using the first node of a linked list to store actual values. Use just as the header of your list. Reason is, if you need to delete this node, you don't lose the list. Just a tip
3) In your first function, if *root==NULL, I'd rather make the function fail than adding it to a temporary list (that's being lost in the current code, see that it adds the value to a list that is not being passed outside the function.
4) Well, you are actually making it go to the right if the new value is greater than the node, to the left if it's smaller than the node, but it never stops. See this example:
Suppose you have the list 1->3->4. Now you want to insert 2. What the algorithm will do? keep trying to insert in the 1 node and 3 node, switching between them, but never actually inserting anything.
Solution: as you will build this list bottom up, your list will always be sorted (inf you insert nodes correctly). So you just need to check if the next node is higher, and if it is, insert right where you are.
5) If you're passing a TreeNode *root as argument (on the 2nd function), you shouldn't have to recreate a new list and make root=newlist. Just use the root.
All of this would result in (didn't test, might be some errors):
void insert_node(TreeNode* root, int toInsert){
if(root==NULL){
printf("Error");
return;
}
TreeNode* temp = root; //I just don't like to mess with the original list, rather do this
if(temp->right!=NULL && toInsert > temp->right->data){ //if toInsert greater than next
insert_node(temp->right, toInsert);
}
else{ //if toInsert is less or equal than next node
TreeNode* temp2 = temp->right; //grabbing the list after this node
temp->right=(TreeNode*)malloc(sizeof(TreeNode)); //making room for the new node
temp->right->right=temp2; //putting the pointer to the right position
temp->right->left=temp; //setting the left of the next node to the current
temp->right->data=toInsert;
}
}
void build_tree(TreeNode* root, const int elements[], const int count){
if(count > 0){
for(int i = 0; i < count; i++){
insert_node(root, elements[i]);
}
}
}
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;
}
}
}
I'm trying to insert nodes into a tree in order. My function works fine... when there's only three nodes.
I have this code:
typedef struct _Tnode Tnode;
struct _Tnode {
char* data;
Tnode* left;
Tnode* right;
};
Along with this:
Tnode* add_tnode(Tnode* current_node, char* value) {
Tnode* ret_value;
if(current_node == NULL) {
current_node = (Tnode*) malloc(sizeof(Tnode));
if(current_node != NULL) {
(current_node)->data = value;
(current_node)->left = NULL;
(current_node)->right = NULL;
ret_value = current_node; }
else
printf("no memory");
}
else {
if(strcmp(current_node->data,value)) { //left for less than
ret_value = add_tnode((current_node->left), value);
current_node -> left = (Tnode*) malloc(sizeof(Tnode));
(current_node -> left) -> data = value;
}
else if(strcmp(current_node->data,value) > 0) {
ret_value = add_tnode((current_node -> right), value);
current_node -> right = (Tnode*) malloc(sizeof(Tnode));
(current_node -> right) -> data = value;
}
else {
printf("duplicate\n");
ret_value = current_node;
}
}
return ret_value;
}
I know what's wrong here, I just don't know how to fix it. This just overwrites the two nodes attached to the root node. i.e.
|root_node|
/ \
|node_2| |node_3|
I can't add a node four. It just overwrites node 2 or 3 depending on the input. After debugging and a little research, I'm not quite sure where to go from here...
If anyone can help, I'd really appreciate it.
You should leave the mallocing only to the case where the insertion reaches a leaf node (ie NULL). In the other cases, all you should do is to traverse to the next level depending on your comparison. In your case, you're traversing to the next level, and then killing it with a new malloc. Because of this you're never getting past the first level.
eg.
if (current_node == NULL) // Do initialization stuff and return current_node
if (strcmp(current_node->data, value) < 0) {
current_node->left = add_tnode((current_node->left), value);
} else if (strcmp(current_node->data, value) > 0) {
current_node->right = add_tnode((current_node->right), value);
}
return current_node;
This would appear to just be a school project.
Where to begin.
1) You are clobbering left/right all the way down the tree. I'm not sure why you would expect them to be preserved since:
a) You always write to these nodes.
b) The only time you return an existing node is on a strcmp match.
2) You really need to check strcmp < 0 on your first compare.
3) For a non-balanced tree, there's no reason to use recursion - you can just use a loop until you get to a leaf and then hook the leaf. If you really want recursion...
4) Recursive... Return NULL in all cases except when you create a node (ie: the first part where you have current == NULL).
5) In the left/right, store the return value in a temp local Node*. Only if the return value is not NULL should you assign left/right.
Even this doesn't feel right to me, but if I started from scratch it just wouldn't look like this at all. :) We won't even get into the memory leaks/crashes you probably will end up with by just pushing 'char *' values around all willy nilly.
struct _Tnode {
char* data;
struct _Tnode * left, * right;
};
typedef struct _Tnode Tnode;
void addNode(Tnode ** tree, Tnode * node){
if(!(*tree)){
*tree = node;
return;
}
if(node->data < (*tree)->val){
insert(&(*tree)->left, node);
}else if(node->data>(*tree)->data){
insert(&(*tree)->right, node);
}
}
for starters - the first strcmp
if(strcmp(current_node->data,value))
is probably not right - this is true for both less than and greater than, and then the second if does not make sense
I guess that you'll need to add a pointer to the parent node to the _Tnode struct.
The problem is that after making your recursive function call to add_tnode, on the left branch, say, you are obliterating that same branch with your malloc. The malloc should only happen when you have recursed down to the point where you will be adding the node, not when you are making a recursive call.
Essentially, in a particular function call, you should either make a recursive call OR malloc a new node, not both.
This also produces a memory leak, probably.
If you aren't implementing this for your own edification, I would just use libavl
You don't need to know the parent of the node. just the value at the current node.
Pseudocode:
add_treenode(root, value)
{
//check if we are at a leaf
if root == null
allocate space for new node.
set children to null
save root->value = value
return root // if you need to return something, return the node you inserted.
//if not, this node has a value
if root->value < value //use strcmp since value is a string
add_tnode(root->left, value)
else
add_tnode(root->right, value)
return NULL
}
This is as clean as it gets when it comes to inserting a new tree node. pass the root and the value of the node you want to insert, and it does the rest.
Once you found out, that current_node->data is not null and compared it with value, you first have to check whether the corresponding pointer current_node->left (or ->right) is already in use (!= NULL).
If it is null, you proceed as you do. That is the case that works fine now.
If not, you have to retest the whole thing against the correspondig node, calling your function again on the cooresponding node. Here some pseudo code:
Wrap the code with:
void Add_node(Tnode* current_node) {
...
else {
if(strcmp(current_node->data,value) < 0) { //left for less than
if(current_node->left != NULL) {
Add_node(current_node->left);
} else {
ret_value = add_tnode((current_node->left), value);
current_node -> left = (Tnode*) malloc(sizeof(Tnode));
(current_node -> left) -> data = value;
} else if(strcmp(current_node->data,value) > 0) {
Add_node(current_node->right);
} else {
...
}
This is called recoursion (a function callin itself) and walk through the tree. To read some node, you have to do a recursive function again. Be carefull that they terminate (here at some point the left or right pointer will be null, thus terminating the recursive calling).