I have a function here that will remove a node from a sorted list of any type.
I am having difficulties with one specific case: when there is 1 node in the list and you want to delete it.
In this case, I want to make the list empty, so when the list is printed out, no data is printed to the screen, but I can't seem to get that result. Just say, for example, the list is of type double, and the list consists of just one node 2.0. If this node is the target for deletion, the proceeding output should be an empty list. Instead my code prints out 0.0.
I am not sure how to handle this error. I have found the specific part of the function where this is to be taken care of, but its implementation escapes me. I first check if the previous node is null, and then check if the list length is equal to 1.
The function returns 1 if it was successful and 0 if it failed.
int SLRemove(SortedListPtr list, void *newObj) {
Node ptr, iterptr, prev = NULL;
if(list==NULL || newObj ==NULL) {
return 0;
}
int size= listlength(list);
for(ptr=list->start; ptr!=NULL; ptr=ptr->next) {
if(list->cf(newObj, ptr->info)==0){//found matching entry in list
//deleting first node;
if(prev==NULL) {
if(size == 1) {
printf("attempting to delete list with 1 node\n");
/*code to delete node where it's the only element in the ist, should make the list empty.*/
return 1;
}
list->start = ptr->next;
destroyNode(ptr);
return 1;
} else {
prev->next = ptr->next;
destroyNode(ptr);
return 1;
}
}
prev = ptr;
}
return 0;
}
Any help you can provide would be much appreciated. Thank you.
The first check should be:
if(list==NULL || list->start == NULL || newObj ==NULL) {
return 0;
}
Once past this check, there's at least one node in the list. If prev == NULL, then you need to set list->start = list->start->next to delete the first node. It doesn't matter if there is one node or more than one node.
The other functions you have need to check for list->start == NULL (or size == 0) to avoid printing garbage.
Using a double pointer can eliminate checking for prev == NULL, but I can't explain for your code since I don't know how node is defined, and it's not really needed, since checking for prev == NULL is just as good. As an example:
typedef struct Node_{
struct Node_ *next;
...
}Node;
/* in the delete function */
Node **ppNode = &list->start; /* ptr to list->start or ...->next */
/* to advance ppNode */
ppNode = &(*ppNode->next);
/* to remove a node from the list */
*ppNode = (*ppNode)->next;
Related
i have a full linked list with data in it, what i want is to fill another linked list with the same data but with a condition, so let say that this is the linked list :
char cl;
int time;
int lng;
C 0 1
D 0 2
B 2 1
A 2 2
i wan to copy from this list to a new empty one but only if (time>0), so the new one will be like this :
B 2 1
A 2 2
i have tried this code but it doesn't work :
void insert(const node * n )// this where i put the pointer of the full node
{
node *head=n;
node *sec; // new node
sec=(node*)malloc(sizeof(node));
do{
if(head->time>0){
strcpy(sec->cl,head->cl);
sec->time= head->time;
sec->lng= head->lng;
head=head->next;
sec=sec->next;
}
else
head=head->next;
}while(head!=NULL);
print(sec) // this will print the new node
}
Help me please. Thank you
I combined all the suggestions from the comments as well as some additional fixes.
Here's the resulting code:
const node* insert(const node * head)
{
node *sec = NULL; // start of the new, second list
node *last = NULL; // points to the last inserted node
while(head!=NULL){
if(head->time > 0){
node* newsec=(node*)malloc(sizeof(node));
newsec->cl = head->cl;
newsec->time = head->time;
newsec->lng = head->lng;
newsec->next = NULL;
//Add the new node to the list:
if(last == NULL){ //This is the first element in the new list
sec = newsec;
}else{
last-> next = newsec;
}
last = newsec;
}
head=head->next;
}
print(sec); // this will print the new node
return sec;
}
Your mistakes:
Wrong memory allocation (You only allocated memory once)
strcpy is not needed (char's don't require a string-copy)
while must be at the beginning of the loop (your code would fail if the given list is empty)
missing semicolon
wrong concatination of the new list
wrong const-correctness (Missing const in node *head=n;)
the internal head-variable is not neccessary (And the parameter-naming n is also not ideal. If you name it "start"/"head"/"begin", the comment wouldn't be neccessary)
Another suggestion: Use an upper case name for your struct, since it makes it easier to distinguish types from variables (should be Node, not node).
Note that you might want to remove the const from the return value type.
// Note: a better function name might be: printNodesWithTime
void insert(const node * pOld )
{
// note: since nothing is done with the new linked list,
// there is no need to actually create it
while( NULL != pOld )
{
if(pPld->time > 0)
{
print(pOld) // this will print the node
}
// step to next old node
pOld = pOld->next;
} // end while
} // end function: insert
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 have to write a program that implements a queue with all sorts of menu options (which are all done). I'm having trouble with my "pop" function.
My program is a restaurant waiting list for employees. Whenever a customer calls in or comes into the restaurant they are put onto the waiting list. The only way to pop (be seated) is if the customer's status is waiting-in-restaurant. I have correctly written the portion that changes a customer from call-in to waiting in restaurant.
Also, if the group size is bigger than the table size, I'm supposed to go to the next node and check if the next group fits the criteria to be seated.
enum status(WAIT,CALL);
typedef struct restaurant
{
//stuff
}list;
//I call pop in the main as follows:
pop(&head, &tail);
void pop(list** head, list** tail)
{
list* temp = *head;
int tableSize;
if(*head == *tail && *tail == NULL)
{
printf("The queue is empty... exitting program... \n");
exit(EXIT_FAILURE);
}
printf("What is the table size? ");
scanf(" %d", &tableSize);
if(temp->groupSize > tableSize || temp->waitStatus == CALL)
while(temp->groupSize > tableSize || temp->waitStatus == CALL)
temp = temp->nextNode;
else
*head = (*head)->nextNode;
if(*tail == temp)
*tail = (*tail)->nextNode;
free(temp);
}
When I display my output it doesn't delete the node in the instance if it has to skip the first person in the queue. However, it does work when the first person meets the criteria. Why is this?
First, your pop seems to allow items in the middle of the list to be removed. While this is doable, it requires you remember what was pointing to the node popped to ensure it is set to the node that is after the node being popped. There are a number of ways to do this.
Also, your empty() condition is off. head will always be NULL if the list is empty provided you're doing your job right on setting newly added node nextNode members to NULL. The comparison against tail or checking tail for NULL is not needed.
Finally, perhaps you may want to consider returning the data from the pop if there was any, and a boolean condition of true/false as the function return result to indicate whether something was taken off. Otherwise, how is your program to know data was retrieved successfully, and what that data was?
Regardless, just using your current mantra of deleting something that matches:
void pop(list** head, list** tail)
{
list *temp = NULL, *prior = NULL;
int tableSize = 0;
if(*head == NULL)
{
printf("The queue is empty... exitting program... \n");
exit(EXIT_FAILURE);
}
printf("What is the table size? ");
scanf(" %d", &tableSize);
temp = *head;
while (temp && (temp->groupSize > tableSize || temp->waitStatus == CALL))
{
prior = temp;
temp = temp->nextNode;
}
if (temp)
{
// only way prior is set is if temp is NOT
// pointing to the first node, therefore *head
// is not changed.
if (prior)
{
prior->nextNode = temp->nextNode;
// if we made it to the tail ptr, then it needs
// to be moved back to the prior node
if (*tail == temp)
*tail = prior;
}
else
{ // first node was removed. so move head to
// the next node (which may be NULL)
*head = temp->nextNode;
}
// release the node
free(temp);
}
}
I'm writing a hashtable as an array of linked lists.Currently I'm trying to have a simple hash table where the key is the index of the array and value is a singly linked list for implementing chaining.
This is my code to delete a node:
Basic Struct:
struct Node
{
int value;
int page;
struct Node *next;
};
int searchAndDelete(int frame,int page,int delete)
{
struct Node** iter;
iter=&hashtable[(page-1)%7];
struct Node** prev=iter;
for(;*iter;iter=&(*iter)->next)
{
if(page==((*iter)->page))
{
if(frame==((*iter)->value))
{
if(delete)
{
(*prev)->next=(*iter)->next;
free(*iter);
}
return 1;
}
}
prev=iter;
}
return 0;
}
For insertion please take a look here, AddNode
When I'm deleting a node, the value for that changes to 0. When I search for the node it gives back that node is not preset aka 0 as output from the function.
Are there any mistakes in my code which I haven't thought about?Am I leaving any memory leaks or any other problems?
Edit
Added this piece of code to the delete function:
int searchAndDelete(int frame,int page,int delete)
{
struct Node** iter;
iter=&hashtable[(page-1)%7];
struct Node** prev=iter;
struct Node** curr=iter;
for(;*curr;curr=&(*curr)->next)
{
if(page==((*curr)->page))
{
if(frame==((*curr)->value))
{
if(delete)
{
if(curr==iter)
{
iter=(*curr)->next;
free(*curr);
}
else
{
(*prev)->next=(*curr)->next;
free(*curr);
}
}
return 1;
}
}
prev=curr;
}
return 0;
}
Problem I'm seeing is that when I delete the first time, the element is not freed, it's value is set to 0, but it still says in the linked list. In the second deletion the value of the last elements goes to some garbage and hence that element will never be deleted in my comparison checks. Can someone shed light on what I might be doing here?
If the hash table you're using is seven elements wide (i.e. 0..6 for indexes), and from your AddNode code, it appears it is, then the arithmetic you're using is suspect for the initial iterator find.
iter=&hashtable[page-1%7];
should likely be:
struct Node** iter = hashtable + (page % 7);
This will give you the address of the element in your hash table at the page location modulus 7, i.e. [0..6].
Also, your delete from your hash table head node doesn't account for clearing the table element itself. You may need to (a) set it to null, or (b) chain in the next ptr. Do that as well. You have the ability to since the hash table and the initial node pointer are both available.
EDIT: OP asked for sample. This is just a quick jot of how this can be done. I'm sure there are plenty of better ways, maybe even ones that compile. This assumes both the page AND frame must match EXACTLY for a node to be considered delete'able.
void searchAndDelete(int frame, int page, int del)
{
struct Node** head = hashtable + (page % hashtable_size);
struct Node* curr = *head;
struct Node* prev = NULL;
while (curr)
{
// if they match, setup for delete.
if ((curr->page == page) && (curr->value == frame) && del)
{
// so long as the header pointer is the active node prev
// will be NULL. move head along if this is the case
if (prev == NULL)
*head = curr->next;
// otherwise, the previous pointer needs it next set to
// reference the next of our vicitm node (curr)
else
prev->next = curr->next;
// victim is safe to delete now.
free(curr);
// set to the new head node if we just deleted the
// old one, otherwise the one following prev.
curr = (prev == NULL) ? *head : prev->next;
}
else
{ // no match. remember prev from here on out.
prev = curr;
curr = curr->next;
}
}
}
Eh, close enough =P
I see couple of issues:
mod operator % needs parenthesis. So change iter=&hashtable[page-1%7]; to iter=&hashtable[(page-1)%7];
Handle the case when you will delete 1st element in linked list. In such cases prev will be same as iter so (*prev)->next=(*iter)->next; will not make any different. You need to update the array to store next element aka (*iter)->next.
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.