The following code snippet is not working right.
void deleteNode(list **start, int pos) {
int currentPosition=0;
list *currentNode;
list *nodToDelete;
currentNode = *start;
if (currentNode == NULL) {
printf("Empty List\n");
} else if (pos == 0 ) {
nodToDelete = *start;
*start = nodToDelete->next;
free(nodToDelete);
} else {
while (currentNode->next != NULL) {
if (currentPosition >= pos -1) {
break;
}
currentPosition++;
currentNode = currentNode->next;
}
if (currentPosition < pos -1 || currentNode->next == NULL) {
printf("No node at given position exists\n");
} else {
nodToDelete = currentNode->next;
currentNode = nodToDelete->next;
free(nodToDelete);
nodToDelete = NULL;
}
}
}
void displayList(list *node) {
if (node == NULL) {
printf("Empty List");
}
while (node != NULL) {
printf("%d\t", node->data);
node = node->next;
}
printf("\n");
}
int main()
{
list *start, *node;
start = NULL;
insertNode(&start, 2);
insertNode(&start, 3);
insertNode(&start, 4);
insertNode(&start, 1);
insertNode(&start, 5);
deleteNode(&start, 3);
displayList(start);
}
When executed the output is
Before Deletion 2 3 4 1 5
After Deletion 2 3 4 0 5
It is supposed to delete 1 but it is inserting 0 at its place.
Here is something that might work --
Replace
currentNode = nodToDelete->next;
with
currentNode->next = nodToDelete->next;
You basically need the node before the nodetodelete to have its next to point to the node that nodetodelete used to point to
Once you've found the node you want to take out of the list, you need to actually take it out. =)
...
nodToDelete = currentNode->next;
currentNode->next = nodToDelete->next;
free(nodToDelete);
...
Besides the problem with currentNode->next = nodToDelete->next; and negative positions you are mixing your ui and your logic. As much as possible you should separate the two.
Sending something to the ui is a way of reporting progress; whether the ui is a command line, a browser or a speaker. Within deleteNode, an empty list or a position that is out of bounds, is not progress. Sequentially both are the same as success - you are done. If you want failure to be to be reported, that should be done where it can lead to a separate sequence...i.e the caller. Also, by mixing in ui, you introduce an unnecessary dependency and failure (what if there's a bug in printf, YOUR function will crash when it doesn't doesn't have to). If you're function returns a defined result, the caller can decide if/how to report that result, including success (your function currently doesn't do so, and the caller has no way telling the difference between sucess or failure).
Related
Is this a right way to do a linked list ? I am having a problem in a big school project and now i want to make sure that this is true.
void addnode(int a){
struct house* tmp = houses[i].next;
while (tmp != NULL) {
tmp = tmp->next;
}
tmp = (struct house*)malloc(sizeof(struct house));
tmp->id=a;
tmp->next=NULL;
}
i figured out that the error can be in other parts of the code. Now i will share the parts i suspect i hope you can help me.
houses[i] is an array of linked lists. if houses[i].id==-1 it is empty
struct house get_house_byid(int id) {
for (int i = 0; i < 1000; i++) {
if (houses[i].id != -1) {
if (houses[i].id == id) {
return houses[i];
}
if (houses[i].next != NULL) {
struct house* tmp = houses[i].next;
while (tmp != NULL) {
if (tmp->id == id) {
return *tmp;
}
tmp = tmp->next;
}
}
}
}
struct house housep;
housep.id = -1;
return housep;//if it cant find that id it returns housep
}
There may be other issues with your code that is not shown, but there are issues with addnode:
addnode does not set the head of the list (i.e. houses[i].next).
Thus, the newly added node is never connected to anything [and is a memory leak].
Ignoring the [obvious] typo/syntax error: void addnode{int a} instead of void addnode(int a).
The loop on tmp discards the pointer to the tail of the list. We need a separate variable (e.g. prev).
Note that i is global. That's fine, but the function would be cleaner if i was an argument to addnode instead.
Don't cast the return of malloc: Do I cast the result of malloc?
Here's is some refactored code. It is annotated:
void
addnode(int i,int a)
{
struct house *tmp;
struct house *prev;
// find the tail of the list
prev = NULL;
for (tmp = houses[i].next; tmp != NULL; tmp = tmp->next)
prev = tmp;
// allocate the new node
tmp = malloc(sizeof(*tmp));
tmp->id = a;
tmp->next = NULL;
// append to the tail of the [non-empty] list
if (prev != NULL)
prev->next = tmp;
// add to front of the empty list
else
houses[i].next = tmp;
}
I have tried to convert this method that is already working in my program to recursive way. Because I was asked to do it. The thing is I have tried see below but in my method when try to add to he position the method value this value is a great number and create segmentation.
This is my method in iterative way:
int researchList_getPosByCountry(tResearchList* list, tCountry *country) {
// Check preconditions
assert(list != NULL);
tResearchListNode *prev = NULL;
int pos;
// check if is an empty list
if (researchList_empty(list)) {
pos = -1;
}
else{
pos = 1;
prev = list->first;
while ((prev != NULL) && !country_equal(prev->e->country, country) ) {
prev = prev->next;
pos++;
}
}
if (prev == NULL) {
pos = -1;
}
return pos;
}
This is my method in recursive way:
assert(list != NULL);
tResearchListNode *prev;
int pos;
// check if is an empty list
if (researchList_empty(list)) {
pos = -1;
}
else{
pos = 1;
prev = list->first;
if ((prev != NULL) && !country_equal(prev->e->country, country) ) {
prev = prev->next;
pos = pos + researchList_getPosByCountry(list, country); //Debugging the segmentation is here
}
}
You will get an endless recursion, since you call researchList_getPosByCountry always starting from the begin of the list; again and again and ...
I suggest you introduce a second (then recursively used) function that calls itself with the respective next node and returns (a) the "greatest" negative number possible if the node was not found (thereby turning any intermediate results on the call stack into a negative one), or return 0 to denote "country found, take the count so far", or "1 + next try" to continue counting. The recursive part could look as follows; you need then to call this one from your int researchList_getPosByCountry(tResearchList* list, tCountry *country) and interpret a negative result accordingly:
int researchList_getPosByCountry(tResearchListNode* node, tCountry *country) {
if (!node) {
return INT_MIN;
} else if (countryEqual(...)) {
return 0;
} else {
return 1 + researchList_getPosByCountry(node->next,country);
}
}
I am trying to create a binary search tree and insert a new node in an iterative way. It is all working well except I am getting a memory leak in this function.
Valgrind says 7 blocks (I am adding 7 nodes) are missing.
I couldn't see where my leak is. I would appreciate another look at my code.
void bst_insert_node(bstree* bst, unsigned long phone, char *name) {
bst_node* current = bst->root;
bst_node* parent = NULL;
bst_node* new = (bst_node *)malloc(sizeof(bst_node));
new->phone = phone;
new->left = new->right = new->parent = NULL;
new->name = malloc(sizeof(char) * (strlen(name)+1));
strncpy(new->name,name,(strlen(name)+1));
while(current != NULL) {
parent = current;
if(phone < current->phone) {
current = current -> left;
}
else if(phone > current->phone) {
current = current -> right;
} else {
free(new);
printf("Diese Nummer ist schon bekannt \n");
return;
}
}
new->parent = parent;
if(parent == NULL) {
bst->root = new;
}
else if(new->phone < parent->phone) {
parent->left = new;
}
else {
parent->right = new;
}
}
Free methods:
void bst_free_subtree(bst_node* node) {
if (node == NULL) return;
bst_free_subtree(node->left);
bst_free_subtree(node->right);
printf("\n Deleting node: %lu \t %s", node->phone,node->name);
free(node);}
void bst_free_tree(bstree* bst) {
if(bst != NULL && bst->root != NULL) {
bst_free_subtree(bst->root);
bst->root = NULL;
}
}
As we all discussed in the comments, your memory leak is that you're not freeing the node->name strings that you have allocated. You need to add two more frees to your code:
in bst_insert_node, in the case where you can't insert the node, free(new->name) before you free(new)
in bst_free_subtree, free(node->name) before you free(node)
There is also an off-by-one error allocating space for a copied string, as in your answer. It might be simplest to just new->name = strdup(name) instead, which will do both the allocate and the copy in one go.
As an aside, if these are phone numbers then I'd probably store them as strings, not integers (or libphonenumber if you want to go the whole hog, but C++ not C) and if there's a problem inserting one then it might be better to return the error to the calling code (e.g. return true if inserted, false if not) and let that raise errors rather than printing from this code.
I'm currently working on a school project where I have to write a few helper functions for Binary Search Trees. One of the functions removes a node from the tree. I'm trying to run some test cases but I can't seem to get them to work. I know the problem has something do with how I'm using pointers, but I'm not quite sure where I'm going wrong.
Here is the code:
int removeBST (struct TreeNode **rootRef, int data)
{
struct TreeNode *current = *rootRef;
struct TreeNode *temp = current;
if (current == NULL)
return 0;
if (data < current->data)
{
current->left = removeBST (¤t->left, data);
}
if (data > current->data)
{
current->right = removeBST (¤t->right, data);
}
if (current->left == NULL || current->right == NULL)
return 0;
else
{
if (current->left == NULL) {
temp = current->right;
current = temp;
free (temp);
return 1;
}
else if (current->right == NULL) {
temp = current->left;
current = temp;
free (temp);
return 1;
}
temp = leftRoot (current->right);
current->data = temp->data;
current->right = removeBST (¤t->right, temp->data);
}
return 1;
}
Note: I didn't include the leftRoot() function, but it's fairly simple and I know it does what it's supposed to (return the leftmost root in a subtree)
Here is the part of the code my professor gave us that tests the remove function:
for(i = -4; i < 25; i+=4)
{
n = removeBST(&bst, i);
if(!n) printf("remove did not find %d\n", i);
}
and in case it's necessary, here's the entire test code that creates the tree and inserts the data:
struct TreeNode* bst = NULL;
for(i = 0; i < 23; ++i)
{
n = (i*17+11) % 23;
bst = insertBST(bst, n);
}
printf("filled BST: ");
printTree(bst);
printf("BST leaves: ");
printLeaves(bst);
printf("BST depth = %d\n", maxDepth(bst));
printf("BST minimum value = %d\n", minValueBST(bst));
printf("BST isBST = %d\n", isBST(bst));
for(i = -4; i < 25; i+=4)
{
n = removeBST(&bst, i);
if(!n) printf("remove did not find %d\n", i);
}
the entire output is:
filled BST: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
BST leaves: 0 6 12 17
BST depth = 8
BST minimum value = 0
BST isBST = 1
remove did not find -4
remove did not find 0
remove did not find 4
(this part repeats all the way up to 24)
BST after removes: 11
Since everything besides the '11' is no longer attached to tree, I'm fairly certain that something in my program is assigning pointers where they shouldn't be assigned and tree nodes are just getting lost in the void. Any ideas?
EDIT: One piece of information I forgot to provide, the deleted node's left-most child is supposed to replace the deleted node.
I'm not sure that I've found all of the issues in your code but here is one major one:
int removeBST (struct TreeNode **rootRef, int data)
Your function returns an int, corroborated by a number of return 1 or return 0 statements...
And yet you do this:
if (data < current->data)
{
current->left = removeBST (¤t->left, data);
}
if (data > current->data)
{
current->right = removeBST (¤t->right, data);
}
Since you're passing ¤t->left to the first argument the I can assume that it's type would be a pointer to a struct TreeNode **rootRef, which is struct TreeNode ***rootRef...
Which means that you're assigning addresses 0 and 1 to the left and right nodes? This seems very odd to me and is likely causing problems for you.
Note: this is not a solution but it is too big to fit into a comment.
Since you've opted for recursion let me see if I can help you fix this somewhat...
int removeBST (struct TreeNode **rootRef, int data)
{
struct TreeNode *current = *rootRef;
struct TreeNode *temp = current;
if (current == NULL)
return 0;
if (data < current->data)
{
// We don't want to modify things here, just let the next
// call take care of it and return what it returns.
return removeBST(¤t->left, data);
}
else if (data > current->data)
{
// Same here.
return removeBST(¤t->right, data);
}
else
{
if (current->left == NULL) {
temp = current->right;
// The rest of the stuff from here moved below.
// Because I added the else, the return isn't needed
// here anymore either, since the one at the bottom
// will return 1 anyway.
}
else if (current->right == NULL) {
temp = current->left;
// I did the same here.
}
else {
temp = leftRoot (current->right);
// This was on the outside but really it should be an else
// since it means less code...
// Additionally, once you got the left root why did you decide
// to remove it too? As far as I can see you only want to
// remove this one... If not, then you might have some work
// to do here...
}
*rootRef = temp; // current and rootRef are not the same.
// You need to use rootRef here so that we
// move the temp pointer to the current one
// (replace it). Think carefully about where
// the pointers are! Pointers also have addresses
// and it matters what address you write to
// where, use pen and paper and draw where things
// point!
free (current); // this means that we can't delete temp! so
// since, we've just deleted the "current"
// pointer we should discard it too...
}
return 1;
}
Draw a diagram for your pointers. I find diagrams like this or this help me most. It is not embarrassing and will help you understand what you're writing. It is important to visualize these things, particularly when you're just learning.
I've tried to fix the code up a little. I will admit that I didn't spend as much time as I possibly should have proof-reading it but it should be ok enough to give you an idea about the solution. Don't just copy/paste this, I don't guarantee it will work. But it should help you get onto the right path.
I've been trying to get this BST working for the last few days, and I am getting stuck on the search function. The logic seems to be correct (unless I'm missing very important details) but there still is something wrong with the code. Could it be because I am dealing with strings? Anyways, here is some code:
EDIT: I've pinpointed somewhere that seems to be going wrong. It turns out that my root is always null. I placed a printf to test if the NULL-case were true, and it always printed true. I've added my tree initialization at the bottom of this question.
The (Updated) Search Function:
//Thank you, M Oehm
node* search(node * tree, char *key)
{
/* char *key is user input */
int cmp;
if(tree == NULL) {
return NULL;
}
cmp = strcmp(key, tree->key);
if(cmp < 0) return search(tree->left, key);
if(cmp > 0) return search(tree->right, key);
return tree;
}
Implementation in main function:
printf("Enter a string to search the tree with: ");
fgets(findNode, MAX_WORD, stdin);
findString = malloc(sizeof(char)*strlen(findNode)+1);
strcpy(findString,findNode);
printf("findString: %s\n", findString);
searched = search(&root, findString);
if(searched == NULL) {
printf("No_such_key\n");
free(findString);
}
else {
printNode(searched);
free(findString);
}
break;
Tree Initialization (via file parsing):
/* Loop through each line in the file*/
while(fgets(buffer, sizeof(buffer), file) != NULL) {
tempToken = strtok(buffer, " \n");
while(tempToken != NULL) {
/* Assign default values */
curr = (node *)malloc(sizeof(node));
curr->left = curr->right = NULL;
curr->key = malloc(sizeof(char)*strlen(tempToken)+1); /* +1 for '\0' */
strcpy(curr->key, tempToken);
curr->frequency = 1;
/* Insert node into tree */
insert(&root, curr);
/* Get next token */
tempToken = strtok(NULL, " \n");
}
}
/* Test insertion worked; close file */
print_inorder(root);
fclose(file);
Insertion Function:
void insert(node ** tree, node * item)
{
/* If no root, item is root */
if(!(*tree)) {
*tree = item;
return;
}
/* If item value is less than node in tree, assign to left */
if(strcmp(item->key,(*tree)->key) < 0) {
insert(&(*tree)->left, item);
}
else if(strcmp(item->key,(*tree)->key) > 0) {
insert(&(*tree)->right, item);
}
else if(strcmp(item->key,(*tree)->key) == 0) {
(*tree)->frequency++;
}
}
The print function shows me that the insertion works properly.
There are two errors in your code: You don't check whetehr the root node, to which you pass a pointer, is null and you don't return the results from the recursive functions.
Your function doesn't modify the tree, so you don't have to pass a pointer to the nodes. That method is useful for functions that modify the tree, e.g. for inserting or deleting nodes. Your function shoul pass a pointer to the root node. That also signals to the user that the tree won't be modified.
So here's a corrected version:
node* search(node *tree, const char *key)
{
int cmp;
if (tree == NULL) return NULL;
cmp = strcmp(key, tree->key);
if (cmp < 0) return search(tree->left, key);
if (cmp > 0) return search(tree->right, key);
return tree;
}
That version must be called like this:
node *hit = search(tree, "bingo!");
Note that this function does the string comparison only once and saves the result in a temporary variable. Your code calls strcmp up to three times.
You don't have to use recursion here. It's even a bit wasteful, because you have to percolate the answer up the first call. Recursion is useful when each step has to maintain a state, which you can represent as local variables. Here, you just change the input node.
Here's a non-recursive variant of the search function:
node* search(node *tree, const char *key)
{
while (tree) {
int cmp = strcmp(key, tree->key);
if (cmp == 0) return tree;
tree = (cmp < 0) ? tree->left : tree->right;
}
return NULL;
}
search(&(*tree)->left, key);
Should be:
return search(&(*tree)->left, key);
Same for the right case.
Try changing your function to something like this.
node* search(node * tree, char * key)
{
if(tree == NULL) {
return NULL;
}
if(strcmp(key,tree->key) < 0) {
return search(tree->left, key);
}
else if(strcmp(key,tree->key) > 0) {
return search(tree->right, key);
}
printf("Success!\n");
return tree;
}
A simple node* would suffice for your problem. No need for double pointers.