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).
Related
Is there something in this that I don't understand or is this one of those times that I'm going to need to use the alloc functions from stdlib.h that I have never used before.
struct node {
int value;
node* left;
node* right;
node* parent;
};
This is the code that makes the program crash.
// Is the value > current node?
// If it is, then go right,
// If not then go left.
// Is there a node forward?
// If not then create a node with the value.
node currentNode = rootNode;
bool newNodeCreated = false;
while (newNodeCreated == false){
if (value > currentNode.value){ // If the value is greater than the currents node.
if (currentNode.right != NULL){ // Check the child on the right.
currentNode = *currentNode.right; // Set the current node to the child and restart the loop.
} else {
currentNode.right->value = value; // Set a new node.
currentNode.right->parent = ¤tNode;
newNodeCreated = true; // End loop.
}
} else { // If the value is less than the current node.
if (currentNode.left != NULL){ // Check the child on the left.
currentNode = *currentNode.left; // Set the current node to the child and restart the loop.
} else {
currentNode.left->value = value; // Set a new node.
currentNode.left->parent = ¤tNode;
newNodeCreated = true; // End loop.
}
}
}
return;
When you create a node, the values inside are set to nonsense ("garbage values") until you explicitly set them. C doesn't do any initialization for you, so the values are whatever was in RAM before you ran your code.
So when you check if the left/right children are NULL, they may be NULL if the random value happens to be 0, but they also may not and may just point to a random memory address that may or may not be in your program's address space. Regardless, another node doesn't actually exist there until you make one.
Allocating memory is pretty simple. To make a new node, all you have to do is
node* newNode = malloc(sizeof(node));
if (!newNode) {
// Your program has run out of memory!
exit(1);
}
and when you want to remove that node, call free on its pointer.
free(newNode);
Once you've actually allocated memory, you can use that pointer to add the new node to the tree.
// ...
} else {
currentNode.right = newNode;
currentNode.right->value = value;
currentNode.right->parent = currentNode;
// Explicitly set right and left on the new node to null
currentNode.right->right = NULL;
currentNode.right->left = NULL;
newNodeCreated = true;
}
// ...
You may want to change currentNode to a node* instead of a node to avoid copying nodes in memory, but that's unrelated to the answer here.
if currentNode.right == NULL , then the first instruction executed is:
currentNode.right->value = value;
you must allocate currentNode.right first.
if (currentNode.right != NULL){ // Check the child on the right.
currentNode = *currentNode.right; // Set the current node to the child and restart the loop.
} else {
currentNode.right->value = value; // Set a new node.
currentNode.right->parent = ¤tNode;
Im working on a Binary Search Tree assignment for class and for this function I need to follow my professor's pseudo code. Unfortunately, I'm not sure about one specific detail, and she refuses to clarify.
Link to the pseudo code is here:
https://imgur.com/a/rhjhEIa
SUBROUTINE insert(current, parent, node)
IF current is null
IF parent is null
root = node
ELSE
ID node.value < parent.value
parent.left = node
ELSE
parent.right = node
END IF
RETURN true
END IF
ELSE IF node.value = current.=value
RETURN false
ELSE IF ode.value < current.value
insert(current.left, current, node)
ELSE
insert(current.right, current, node)
END IF
END SUBROUTINE
In place of node, I've tried seemingly most of the allowed variables, including current, parent, (and even value, which didn't work. Shocker.)
bool recursiveInsert(Node* current, Node* parent, double value)
{
if (current == NULL)
{
if (parent == NULL)
{
}
else
{
if (current->value < parent->value)
{
parent->left = current;
}
else
{
parent->right = current;
}
return true;
}
}
else if(parent->value == current->value)
{
return false;
}
else if (parent->value < current->value)
{
insert(current->left, current->value, current);
}
else
{
insert(current->right, current->value, current);
}
}
I expect the output to add the value to the binary search tree and return true, but the program currently just throws a error whenever I get to the parts that require "node".
node in the context of the pseudocode is a previously allocated node containing the data being inserted into the tree. The initial caller allocates it (which is both pointless and never done in RW code).In reality, it is highly unlikely to actually do this pattern unless you're considering a library that potentially moves nodes out of one tree into another, and you want to avoid the expense of setting-up/tearing-down the nodes themselves.
Regarding the algorithm, it's fairly straightforward, though not very pretty:
If both current and parent are null, it means this must be the first node in the tree tracked by some global pointer root. Therefore, root is assigned the incoming node directly.
Otherwise, If current is null but parent is not if means parent is some potential leaf in the tree (meaning it has either a left, a right, or both contained pointers that are null), and you've landed on the null pointer. The insertion requires comparing against the parent value to know whether you hang the node on the left or the right. Note that this is inefficient, as you already did this comparison (it's how you got here in the first place).
Otherwise if current is not-null we simply check whether the values are equal, or less (greater is assumed if neither of those are true), and drive into the subtree of left or right if warranted. In that case, current.left or current.right become the recursed current, and current becomes the parent of said-same recursive call.
That's it. That's how that algorithm works. And frankly, it's marginal.
To implement this algorithm with your argument list (that takes a value rather than a node for the final argument), you need only ensure node allocation only happens when it is time to actually hang it, and only then (there are two such cases.
bool recursiveInsert(Node* current, Node* parent, double value)
{
bool result = false;
if (current == NULL)
{
if (parent == NULL)
{
root = malloc(sizeof *root);
root->value = value;
root->left = root->right = NULL;
}
else
{
Node *p = malloc(sizeof *p);
p->value = value;
p->left = p->right = NULL;
if (value < parent->value)
{
parent->left = p;
}
else
{
parent->right = p;
}
result = true;
}
}
else if (value < parent->value)
result = recursiveInsert(current->left, current, value);
else if (parent->value < value)
result = recursiveInsert(current->right, current, value);
return result;
}
When inserting a value into the tree, the call will look something like this:
recursiveInsert(root, NULL, value);
It's not pretty, but it works. That it relies on global root presence is probably the worst part of this algorithm. The multi-compare is probably second on the list of yuck.
A Different Approach
Ideally the root of the tree is passed in as an argument. Further, we can make the algorithm recursive as it is now, but no longer rely on some global root. Finally, we can reduce the argument count to two: the address of a pointer (initially the address of the root pointer), and the value being inserted. sing a pointer-to-pointer as the tree access method makes this algorithm elegant, whether using recursion or not. Both are provided below:
Recursive Insertion
bool treeInsert(Node **pp, double value)
{
bool result = false;
if (!*pp)
{
*pp = malloc(sizeof **pp);
(*pp)->value = value;
(*pp)->left = (*pp)->right = NULL;
result = true;
}
else if (value < (*pp)->value)
{
result = recursiveInsert(&(*pp)->left, value);
}
else if ((*pp)->value < value)
{
result = recursiveInsert(&(*pp)->right, value);
}
return result;
}
Iterative Insertion
bool treeInsert(Node **pp, double value)
{
bool result = false;
while (*pp)
{
if (value < (*pp)->value)
pp = &(*pp)->left;
else if ((*pp)->value < value)
pp = &(*pp)->right;
else break;
}
if (!*pp)
{
*pp = malloc(sizeof **pp);
(*pp)->value = value;
(*pp)->left = (*pp)->right = NULL;
result = true;
}
return result;
}
in either case, you invoke by passing the address of the root pointer (thus a pointer to pointer), where an empty try is signified by a NULL root:
treeInsert(&root, value);
Either function will accomplish the task at hand. I leave the error-hardening asa task for you (check your mallocs).
As you have mentioned, this is a function to insert a node in a binary search tree. The parameters are as follows
parent is the parent of the node being examined. This would be called with the root of the tree.
current is the left or right of the parent node being examined. While calling the function for the first time, you should use root->left if the value of the current node is less than root, or root->right if the value is greater than root. If root is null, then current should also be NULL
if (root == NULL)
{
ret = recursiveInsert(NULL, NULL, node);
}
else if (root->value < node->value)
{
ret = recursiveInsert(root->left, root, node);
}
else if (root-> value > node->value)
{
ret = recursiveInsert(root->right, root, node);
}
else
{
//same value, handle error
}
node is the new node to be added to the tree. The memory allocation for this node should be done before the call to recursiveinsert and the value should be specified.
Now let us look at the code that you have written.
The first mistake is to have the third parameter as a double. This should be a parameter of type node which should have already been allocated before.
From the condition check that
ELSE IF node.value = current.=value
RETURN false
it seems that node->value is of integer type.
Taking all this into consideration, the updated code is below.
Node* root = NULL; //global variable
...
bool recursiveInsert(Node* current, Node* parent, Node* node)
{
if (current == NULL)
{
if (parent == NULL)
{
root = node;
}
else
{
if (current->value < parent->value)
{
parent->left = node;
}
else
{
parent->right = node;
}
return true;
}
}
else if(node->value == current->value)
{
return false;
}
else if (parent->value < current->value)
{
recursiveInsert(current->left, current, node);
}
else
{
recursiveInsert(current->right, current, node);
}
}
I have a linked list, I guess a tree looks like this:
-> grandma
-> dad
-> me
-> sister
-> niece
-> brother
-> uncle
-> cousin
and I have a struct as following
struct Node{
Node *parent;
Node *next;
Node *child;
}
How would I free that linked list?
My idea is to do a depth first search and deallocate each node?
Recursive depth-search (DFS): You're right, it's a good way to dealocate binary-tree memory:
remove(node):
if node is null: return
//else
remove(left node)
remove(right node)
free(node)
Iterative solution:
https://codegolf.stackexchange.com/questions/478/free-a-binary-tree
Since you don't want to use any recursive solution, there you can find well-described iterative one.
You can optimize allocation/deallocation of the tree.
Imagine, you want to create tree with 20 or 30 persons. You can allocate an array of 30 Node structs:
size_t currentArraySize = 30;
Node* nodes = (Node*)malloc(currentArraySize * sizeof(Node));
size_t nextFreeIndex = 0;
To add new element you can write simple function:
Node* allocateNode()
{
// Oops! There's not more memory in the buffer.
// Lets increase its size.
if (nextFreeIndex >= currentArraySize) {
currentArraySize *= 2;
Node* newNodes = (Node*)realloc(nodes, currentArraySize * sizeof(Node));
// Should correct pointers (thanks to user3386109)
if (newNodes != nodes) {
for (size_t i = 0; i < nextFreeIndex; i++) {
if (newNodes[i]->parent != NULL)
newNodes[i]->parent -= nodes += newNodes;
if (newNodes[i]->next != NULL)
newNodes[i]->next -= nodes += newNodes;
if (newNodes[i]->child != NULL)
newNodes[i]->child -= nodes += newNodes;
}
}
}
return nodes[nextFreeIndex++];
}
To deallocate all nodes you can just free the single pointer nodes.
Now the code looks a little scary as wrote user3386109, so we may simplify it a little:
Node* allocateNode()
{
// Oops! There's not more memory in the buffer.
// Lets increase its size.
if (nextFreeIndex >= currentArraySize) {
currentArraySize *= 2;
Node* newNodes = (Node*)realloc(nodes, currentArraySize * sizeof(Node));
// Should correct pointers (thanks to user3386109)
if (newNodes != nodes)
correctPointers(newNodes, nodes);
}
return nodes[nextFreeIndex++];
}
#define correctPointer(pointer, oldOffset, newOffset) if (pointer != NULL) { \\
pointer -= oldOffset; \\
pointer += newOffset; \\
}
void correctPointers(Node* newNodes, Node* nodes)
{
for (size_t i = 0; i < nextFreeIndex; i++) {
correntPointer(newNodes[i]->parent, nodes, newNodes);
correntPointer(newNodes[i]->child, nodes, newNodes);
correntPointer(newNodes[i]->next, nodes, newNodes);
}
}
Iterative version, inspired by Day–Stout–Warren algorithm:
void removetree(Node *node)
{
while(node != NULL)
{
Node *temp = node;
if(node->child != NULL)
{
node = node->child;
temp->child = node->next;
node->next = temp;
}
else
{
node = node->next;
remove(temp);
}
}
}
This algorithm somewhat like tries to convert the tree into a list single-linked with next pointers, which is very simple to destroy just by iterative unlinking and destroying the first item. However it never completes the conversion, because it unlinks and removes the head node as soon as it can, despite the rest of tree not being converted yet. So to say, it interleaves a relink step with unlink-and-destroy step.
We test with the if instruction whether the first (head) node has any children. If so, we make its child a new head and the current node becomes the new head's next node. This way we have one more next link in the first-level list. What was 'next' to the now-head node becomes a child to a previous-head node, which is now the head's first next.
On the other hand if the head node has no children, it may be removed and its next becomes a new head.
These two steps are iterated by the while loop until all children are converted into siblings and removed afterwards.
You may use recursive solution
free(root)
{
if (root->next == null)
{
free(node)
}
free(root->left)
free(right->)
}
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.
I have written a function below that takes a pointer to the front of a linked list and determines if the values in that list are stored in strictly ascending order. If this is the case, the function should return 1; otherwise it should return 0.
struct listnode {
int data;
struct listnode* next;
};
int ascendingOrder(struct listnode* front) {
struct listnode* current = front;
if(current->data == NULL)
return current->data;
while(current->next != NULL) {
if(current->data < current->next->data)
return 1;
}
else
return 0;
}
}
Would this work, and if not how come?
I see a few things that don't look right. For starters, your version won't even compile. In addition, if the first item is less than the second item, your function returns. It doesn't even check the other items.
I'd do something more like this (untested).
int IsAscending(struct listnode* node)
{
if (node == NULL)
return TRUE;
while(node->next != NULL)
{
if (node->data > node->next->data)
return FALSE;
node = node->next;
}
return TRUE;
}
This wouldn't work because you return after comparing the first two list items. You could put "continue;" (or just leave it blank) where your return 1 is, then put return 1 outside the while loop at the end of the program. That way it only returns 0 if it runs into a point where current > next and returns 1 if it gets through all items without that happening. Also your brackets are off, you have an extra one right after return 1. and you aren't ever changing the current node to the next node, you must set that at the bottom of the while loop.