I have a question about these two algorithms:
This works normally:
node* deleteTree(node* root)
{
if(root != NULL)
{
deleteTree(root->left);
deleteTree(root->right);
deallocateNode(root);
}
return root=NULL;
}
This nope:
void deleteTree(node* root)
{
if(root != NULL)
{
deleteTree(root->left);
deleteTree(root->right);
deallocateNode(root);
}
root=NULL;
}
Why? I need to set the root to null so the node pointer after the delete of the BST will not point to a memory not allocated.
I prefer the second algorithm because the recall of the function is more intuitive.
Theoretically, the two algorithms are equivalent but if I use the second algorithm and I try to print the BST, the program goes in a loop.
When you have node *root and assign node = NULL it won't affect its value in exterior. If you want to modify the pointer value, you'll have to pass a double pointer.
Something like:
void deleteTree(node** root)
{
if(*root != NULL)
{
deleteTree(&((*root)->left));
deleteTree(&((*root)->right));
deallocateNode(*root);
}
*root = NULL;
}
But I don't really think you need to assign node = NULL since you free it. So, you can just assign node = NULL after you call deleteTree and you won't need to mess with double pointer.
Related
I try to delete a word (char* value) from a linked list but I am getting an exception when I compare my word to the links list node word.
EXC_BAD_ACCESS (code=1, address=0xa00000002)
I'm not sure why this is happening, I would appreciate to get any solution to the problem.
LinkedList* DeleteWordElement(LinkedList* head, char* value){
LinkedList *previous=head, *current=head->next;
if (head == NULL)
return head;
if (head->data == value)
{
LinkedList *temp = head;
head = head->next;
free(temp);
return head;
}
while (previous!=NULL)
{
if (previous->data == value) // Exception
break;
current = previous;
previous = previous->next;
}
if (previous != NULL)
current->next = previous->next;
free(previous);
return head;
}
Before doing:
LinkedList *previous=head, *current=head->next;
you need to check if the head is NULL. Then you should use strcmp, instead of ==, to compare the C-string value:
strcmp compares the actual C-string content, while using == between
two C-string is asking if these two char pointers point to the same
position. (source)
Finally, you do not need to keep the previous pointer, the current->next pointer is enough:
LinkedList* DeleteWordElement(LinkedList* head, char* value){
if (head == NULL)
return head;
if (strcmp(value, head->data) == 0){
LinkedList *next = head->next;
free(head);
return next;
}
LinkedList *current=head;
while (current->next != NULL){
if (strcmp(value, current->next->data) == 0){
LinkedList *next = current->next;
current->next = current->next->next;
free(next);
break;
}
current = current->next;
}
return head;
}
The code can be shorten if you use the recursive version, albeit at the cost of performance:
LinkedList* DeleteWordElement(LinkedList* current, char* value){
if(current != NULL){
if (strcmp(value, current->data) == 0){
LinkedList *result = current->next;
free(current);
return result;
}
current->next = DeleteWordElement(current->next, data);
}
return current;
}
As has already been pointed in the other answer and in the comments section, the expression
current=head->next
will cause undefined behavior when head == NULL.
Another problem is that the expression
head->data == value
does not compare the actual string contents, but instead it compares the pointers themselves (i.e. the memory addresses). This is not what you want, because the pointers will probably always be different, even when the string contents are identical. In order to compare the actual string contents, you must use the function strcmp instead.
The other answer already contains a solution to the problem. However, I would like to provide an alternate solution, which is shorter and more efficient for the computer, but is maybe harder to understand for a programmer, because it uses double pointers (i.e. pointers to pointers):
LinkedList* DeleteWordElement( LinkedList *head, char* value )
{
LinkedList **pp = &head, *p;
while ( (p=*pp) != NULL )
{
if ( strcmp( p->data, value ) == 0 )
{
//found node, so unlink and remove it
*pp = p->next;
free( p );
break;
}
pp = &p->next;
}
return head;
}
As you can see, this solution only requires a single if statement, in contrast to the code in your answer which requires 4 if statements and the other answer, which requires 3 if statements. These additional if statements are not necessary when using double pointers, because the same code can handle all cases. Therefore, you don't need to introduce additional code paths for every single case. As a consequence, this solution also has no need for code duplication.
It is also worth mentioning that the function signature
LinkedList* DeleteWordElement(LinkedList* head, char* value)
is a bit inefficient. The return value is the new head, so the code that calls the function must update the list head based on the return value. It would be simpler if the code that calls the function simply passes the address of the list head pointer, so the function can update the list head itself, when necessary. That way, the code which calls the function won't have to do any additional work.
In order to accomplish this, you can change the function signature to the following:
void DeleteWordElement( LinkedList** pp_head, char* value )
Because the address of a pointer is a pointer to a pointer (i.e. a double pointer), you must now use ** instead of only *.
Also, now that you are no longer using the return value of the function, you may want to use it for something else. For example, you may want the function to return whether the value was found or not. Therefore, you may want to change the signature to the following:
bool DeleteWordElement( LinkedList** pp_head, char* value )
Now you can make the function return true when the value was found, otherwise return false to indicate that the value was not found. Note that you must #include <stdbool.h> to have access to bool, true and false.
Although we have made the function more powerful by adding the boolean return value, it is just as simple as what we had before.
bool DeleteWordElement( LinkedList **pp_head, char* value )
{
LinkedList **pp = pp_head, *p;
while ( (p=*pp) != NULL )
{
if ( strcmp( p->data, value ) == 0 )
{
//found node, so unlink and remove it, and then return true
*pp = p->next;
free( p );
return true;
}
pp = &p->next;
}
//return false because we did not find any matching node in the list
return false;
}
I am working on a C binary search tree library and I'm trying to write a function that will delete the left node of the tree subtree. Here's the struct of my tree:
struct Node {
int value;
struct Node *left;
struct Node *right;
};
typedef struct Node TNode;
typedef struct Node *binary_tree;
The tree is created like this:
binary_tree NewBinaryTree(int value_root) {
binary_tree newRoot = malloc(sizeof(TNode));
if (newRoot) {
newRoot->value = value_root;
newRoot->left = NULL;
newRoot->right = NULL;
}
return newRoot;
}
Adding element to it:
void Insert(binary_tree *tree, int val) {
if (*tree == NULL) {
*tree = (binary_tree)malloc(sizeof(TNode));
(*tree)->value = val;
(*tree)->left = NULL;
(*tree)->right = NULL;
} else {
if (val < (*tree)->value) {
Insert(&(*tree)->left, val);
} else {
Insert(&(*tree)->right, val);
}
}
}
The delleftsubtreenode I did:
void delleftsubtree(binary_tree *tree){
if( (*tree)->value!=NULL )
{
free(&(*tree)->left);
delleftsubtree( &(*tree)->left);
}
else
{
printf("end");
}
}
This method compile,however when I try to call it the program just crash.I dont understand why or how else to do that function.
thank you!
As Olaf said in his comment, you have several problems; calling "free()" with a pointer then attempting to dereference it, and use of double indirection.
binary_tree* tree; /* why use a pointer to a pointer? */
Unless you intend to change the value of the pointer, this is extra work you don't want to be doing. All those "(*tree)->member" expressions are not needed if you follow the usual conventions, and I'm not convinced that you understand what "&(*tree)->left" is doing.
I'm not saying that you should never use a pointer to a pointer, I've done it myself, however you should only do it when there is a reason to be changing the value of the referenced pointer, or with a volatile pointer that might be changed by some external actor; this is unlikely and fairly rare outside of garbage collected and compacted pools (strings in some BASIC interpreters, for example) and the like.
Keep in mind that the "left" subtree of a node in the tree is a binary tree itself; it has both left and right nodes. You need to write a function that deletes a subtree at and below a given node. Once that's understood, removal of the left subtree below a node is as simple as:
void delSubtree(NodeT* subRoot)
{
if (subRoot != NULL)
{
delSubtree(subRoot->left);
delSubtree(subRoot->right);
free(subRoot);
}
}
void delLeftSubtree(NodeT* root)
{
if (root != NULL)
{
delSubtree(root->left);
root->left = NULL;
}
}
If this is homework, you should be solving these problems yourself, and I'm doing you no favors in giving you code samples. Understanding how to use pointers and linked data structures (lists, trees, and other graphs) is essential to becoming an accomplished C programmer.
I would like to know if it is possible to free an entire binary search tree in preorder mode. I've got this function:
void preorder_del(struct s_nodo ** tree)
{
if (*tree != NULL)
{
free(*tree);
preorder_del(&(*tree)->left);
preorder_del(&(*tree)->right);
}
}
I don't think this works, freeing the first leaf of the tree wont let me recall preorder, right?
You should record left and right locally to avoid accessing freed pointer after free(*tree).
if (*tree != NULL)
{
struct s_nodo *l = (*tree)->left;
struct s_nodo *r = (*tree)->right;
free(*tree);
preorder_del(&l);
preorder_del(&r);
}
Please help me with this. I keep getting seg faults!
I want to use recursion to create and insert a new node.
Please help me debug this.
//Create a Binary Search Tree From an array.
struct Tree
{
int data;
struct Tree *lchild;
struct Tree *rchild;
};
struct Tree *root = NULL;
struct Tree *node(int val)
{
struct Tree *tempnode;
tempnode = (struct Tree*)malloc(sizeof(struct Tree));
tempnode->data = val;
tempnode->rchild = NULL;
tempnode->lchild = NULL;
return tempnode;
}
void createTree(struct Tree *curr, int val)
{
struct Tree *newnode = node(val);
if (curr == NULL)
curr = newnode;
else if(val < curr->data)
{
createTree(curr->lchild,val);
}
else if(val > curr->data)
{
createTree(curr->rchild,val);
}
else
printf("Error Similar data found\n");
}
void inorder(struct Tree *root)
{
if (root->lchild != NULL)
inorder(root->lchild);
printf("[%d] ",root->data);
if (root->rchild != NULL)
inorder(root->rchild);
}
int main()
{
// root = NULL;
int i = 0, arr[5] = {41,12,32,23,17};
for(i;i<5;i++)
createTree(root,arr[i]);
inorder(root);
return 0;
}
why do I keep getting seg fault. Can someone explain me?
Am I doing something I should not? Or am I missing at some point?
Learn to use a debugger!
Stepping through the main function, you would have seen that the value of root would have remained NULL after each call to createTree
The createTree function is not modifying the value of root, but only modifying its copy of the value of root.
Your createTree function needs to take a struct Tree **curr, a pointer-to-a-pointer. This allows the function to modify the original value, not the local copy.
The root of the tree is not assigned anywhere; in your function createTree you probably think that it is assigned in:
if (curr == NULL)
curr = newnode;
But curr is local to the function and does not affect root. You need to change the argument curr to be a pointer to pointer, otherwise the function does not work for assigning the root node, or child nodes. The root of the tree is not assigned anywhere; in your function createTree you probably think that it is assigned in:
if (curr == NULL)
curr = newnode;
But curr is local to the function and does not affect root even if you gave it as the argument curr. You need to change the argument curr to be a pointer to pointer, otherwise the function does not work for assigning the root node, or child nodes. That is, the function declaration becomes:
void createTree(struct Tree **curr, int val)
Of course you must then change the use of curr inside the function accordingly (i.e., the address pointed to is *curr where it used to be curr), calls of the function need to pass the address, and not value, of the pointer (e.g., createTree(&root, arr[i])).
edit: Or, indeed, have the function return curr and always assign the return value to the relevant pointer at every place where you call createTree, thanks to #JonathanLeffler for the observation.
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).