Single Linked List - Delete From middle - c

I am trying to figure out an algorithm to delete from the middle of a linked list..
My idea is to traverse the list, find the node right before the node I want to delete, call it Nprev, and set Nprev to Nnext where Nnext is after the node to delete Ndelete.
So Nprev -> Ndelte -> Nnext.
My problem is that I cannot figure out how to traverse this list to find the node before the one I want.
I've been doing this with seg faults because I assign pointers out of range I assume.
Its a very messy algorithm that I have, with many if else statements..
Is there an easier way to do this?
Basically I need to go through the list, apply a function to each node to test if
it is true or false. If false I delete the node.
Deleting first and last is not as hard but middle stumped me.
Please let me know if there are some general ways to solve this problem. I've
been scouring the internet and found nothing I need.
I used this: http://www.cs.bu.edu/teaching/c/linked-list/delete/
but the algorithm before step 4 only deletes the first node in my list
and doesn't do any more.
How can I modify this?
They also give a recursive example but I don't understand it and am intimidated by it.

First you need to find the middle node.
Well take 3 pointers fast, slow, prev
with fast moving with twice the speed of slow and prev storing the address of the node previous of slow.
i.e.
*slow=&head,*fast=&head,prev=Null
traverse the list and when fast=NULL
slow will point to the middle node if number of elements are odd and prev will store the address of node previous of the mid node.
so simply
prev->next=slow->next.

Here an example of something I use to search and remove by index:
Given this struct: (Can also be adapted to other self referencing structs)
struct node
{
S s;
int num;
char string[10];
struct node *ptr;
};
typedef struct node NODE;
Use this to remove an item from somewhere in the "middle" of the list (by index)
int remove_by_index(NODE **head, int n) /// tested, works
{
int i = 0;
int retval = -1;
NODE * current = *head;
NODE * temp_node = NULL;
if (n == 0) {
return pop(head);
}
for (int i = 0; i < n-1; i++) {
if (current->ptr == NULL) {
return -1;
}
current = current->ptr;
}
temp_node = current->ptr;
retval = temp_node->num;
current->ptr = temp_node->ptr;
free(temp_node);
return retval;
}

Related

C linked list define how to reimplement a list

Hi this is probably a stupid question to ask with a simple solution but I just can't find an answer in the internet.
So I was exercising for an exam and worked on an assignment. The program has the job to find out what the value in the center of a linked list is (if the length of the list is an odd number)
The structdef is:
typedef struct IntList IntList;
struct IntList {
int value;
IntList* next;
};
and my exact problem right now is that I get a segmentation fault when I try using:
list = list->next;
I want to go step by step in a loop to go to the wished list at the nth position (the center) of the linked list.
Someone knows how I have to rewrite this? If you need more Information to help just say so and I will explain more.
With that function I check the length of the list and in my other function I have a loop which only goes to the mid of the length.
int length_list(IntList* list) {
int n = 0;
for(IntList* node = list; node != NULL; node = node->next) n++;
return n;
}
After this loop ends for(IntList* node = list; node != NULL; node = node->next) n++; you surely have node==NULL.
That is not immediatly a problem.
But depending on what you do with the value of n which you return you might have an off-by-one problem. E.g. in a list with exactly one entry (1 is odd after all), the attempt to use a value which is 1 too high could result in an attempt to access a non-existing node.
Because of this I suspect that your problem might be solved by changing the loop to
for(IntList* node = list; node->next != NULL; node = node->next) n++;, so that it ends on the last existing node, instead of behind. The return value will be lower, whatever you do with it will be "more-careful".
That or try something similar with the small code fragment you show and ask about, list = list->next; only do that if the next is not NULL, not if only list is not NULL.

Segfault when accessing next node in singly linked list

I'm trying to just reverse a singly linked list, but with a bit of a twist. Rather than having the pointer to the next node be the actual next node, it points to the pointer in that next node.
struct _Node
{
union
{
int n;
char c;
} val;
void *ptr; /* points to ptr variable in next node, not beginning */
int var;
};
typedef struct _Node Node;
I know how to reverse a normal singly linked list and I think I have the general idea of how to go about solving this one, but I'm getting a segfault when I'm trying to access head->ptrand I don't know why.
Node *reverse(Node *head)
{
Node * temp;
Node * prev = NULL;
while(head != NULL)
{
temp = head->ptr + 4; /* add 4 to pass union and get beginning of next node */
head->ptr = prev;
prev = head;
head = temp;
}
return prev;
}
Even if I try and access head->ptr without adding 4, I get a segfault.
The driver that I have for this code is only an object file, so I can't see how things are being called or anything of the sort. I'm either missing something blatantly obvious or there is an issue in the driver.
First, I'll show you a major problem in your code:
while (head) // is shorter than while(head != NULL)
{
// Where does the 4 come from?
// And even if: You have to substract it.
// so, definitively a bug:
// temp = head->ptr + 4; /* add 4 to pass union and get beginning of next node */
size_t offset_ptr = (char*)head->ptr - (char*)head;
// the line above should be moved out of the while loop.
temp = head->ptr - offset_ptr;
Anyways, your algorithm probably won't work as written. If you want to reverse stuff, you are gonna have to work backwards (which is non-trivial in single linked lists). There are two options:
count the elements, allocate an array, remember the pointers in that array and then reassign the next pointers.
create a temporary double linked list (actually you only need another single reversely linked list, because both lists together form a double linked list). Then walk again to copy the next pointer from your temporary list to the old list. Remember to free the temporary list prior to returning.
I tried your code and did some tweaking, well in my opinion your code had some logical error. Your pointers were overwritten again and again (jumping from one node to another and back: 1->2 , 2->1) which were leading to suspected memory leaks. Here, a working version of your code...
Node *reverse(Node *head)
{
Node *temp = 0;
//Re-ordering of your assignment statements
while (head) //No need for explicit head != NULL
{
//Here this line ensures that pointers are not overwritten
Node *next = (Node *)head->ptr; //Type casting from void * to Node *
head->ptr = temp;
temp = head;
head = next;
}
return temp;
}

Swapping 2 Nodes in a Linked List

Good day guys, im new here to C and am trying to learn linked lists. I been trying to swap 2 nodes from within a linked list but so far have been having trouble getting it to work. The code I been trying to use causes an endless circular loop, but I don't think it is because of the if or while statement.
Take a look? Any pointers here? Help would be greatly appreciated.
Basically, the code uses a user input to search for a node based on the data inside, then it should swap the node with the data inside with the next node. Been at this for 3 hours, can anybody help? Thanks!
/conductor is the name im using of the pointer for the current node/
#include <stdio.h>
#include <stdlib.h>
struct node {
int x;
struct node *next;
struct node *prev;
};
struct node *root;
struct node *conductor;
struct node *counter;
struct node *newnode;
struct node *back;
struct node *swapper;
struct node *swappee;
struct node *blanker;
int add = 0;
int initialization = 0;
int query = 0;
int swap ()
{
printf("enter data to search from within the nodes: ");
fflush(stdin);
scanf("%d", &query);
conductor = root;
while ( conductor->next != 0)
{
if(conductor->x == query)
{
printf("\n%d\n", query);
swapper = conductor;
swappee = conductor->prev;
conductor = swappee;
conductor->next = swapper;
break;
}
else
{
conductor = conductor->next;
}
}
mainMenu ();
}
A double linked list (like the one you have) is basically an array of node, each node pointing to its neighbors. Let's say we have nodes -A-B-C-D- (A-B means that A points to B and B points to A). Let's say you want to swap B and C. You have to make 4 changes:
Make A point to C
Make C point to B and A
Make B point to D and B
make D point to B
You make only the second and the third change. So, you need to add A->next = B and D->prev=C. I hope it is clear enough.
Also, you should not fflush input streams.
If you want to swap the data:
if (conductor->x == query) {
int temp = conductor->x;
if (conductor->next)
conductor->x = conductor->next->x;
conductor->next->x = temp;
}
}
Typically that is what you will want to do. If you have a structure with several members instead of the 1 int, swapping the pointers may seem less messy in theory, but it isn't, primarily due to the fact that you must test for existence of a next/previous node so often. In truth, you'd probably want a pointer to a separate structure in such a case.
Given three nodes — previous, current, and next, pointing to current->prev, current, and current->next respectively — you must update at most 6 pointers:
next->prev = previous
previous->next = next
current->prev = next
current->next = next->next
next->next = current
current->next->prev = current
Step 2 is not necessary if previous is NULL.
Step 7 is unnecessary if current->next is NULL.
The entire thing is unnecessary if next is NULL.
If you want to swap with the previous node instead of the next, exchange any instance of the variable previous with the variable next and vice-versa as well as exchanging any instance of ->prev with ->next and vice-versa.
Overall, this requires a fair bit of branching code, which can be slow. This is why it is usually better to swap the data rather than messing with the pointers. It gets even messier when you want to swap with the previous node and you only have a singly-linked list that points to the next node because you must store yet another pointer for the equivalent of previous->prev, assuming previous exists.

C - Linked Lists

I am trying to understand the code of linked lists. I understand how they work.
I am looking at some code to do with dynamic memory and linked lists, I have simplified it here:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
char *word;
struct node *next;
} node;
void display_word(node *start) {
node *start_node = start;
puts("");
for(; start_node != NULL; start_node = start_node->next) {
printf("%s", start_node->word);
}
}
node* create_node(char *input) {
node *n = malloc(sizeof(node));;
n->word = strdup(input);
n->next = NULL;
return n;
}
int main() {
node *start_node = NULL;
node *n = NULL;
node *next_node = NULL;
char word_holder[20];
for(; fgets(word_holder,80,stdin) != NULL; n = next_node) {
next_node = create_node(word_holder);
if(start_node == NULL)
start_node = next_node;
if(n != NULL)
n->next = next_node;
}
display_word(start);
}
So the program creates a linked list of each word the user enters and then it prints it out.
What I dont understand is in the main() function where next_node is assigned to a new node everytime to create a new one, but start_node points to next_node, so it will point to every new node that next_node creates each time? So how is it possible to still keep the list? Shouldn't we lose the old node each time?
Can someone explain please.
When the first node is created, a pointer to it is saved in start.
When subsequent nodes are created, they are added at the end of the list, so start still points to the first node, and through it, the rest of the list.
Step through the code with a debugger, or get out a pencil and paper and draw what's happening as you step through in your brain, and you'll see how it all gets put together.
When the first node is created, a pointer to it is saved in start.
After every iteration of the loop, "n" is set to the node just created, because the last piece of the for loop (;n = next) is executed after every iteration of the loop. So mid loop execution "n" will always be pointing to the previous node. Therefore the statement n->next = next is setting the previous node's "next" pointer to the new node.
So during the second iteration of the loop, n = start, and start->next is set to "next" the node you just created.
I hope this answers your question - every time you are updating "next", you're setting that to be yet another new node. Each node has their own "next" that leads to the next node, so you aren't going to lose anything by doing it this way. I didn't actually test your code but since "Start" points to the first node always, you aren't going to lose any nodes along the way. A debugger should help if you're curious to learn more about how this works!

Deleting a middle node from a single linked list when pointer to the previous node is not available

Is it possible to delete a middle node in the single linked list when the only information available we have is the pointer to the node to be deleted and not the pointer to the previous node?After deletion the previous node should point to the node next to deleted node.
It's definitely more a quiz rather than a real problem. However, if we are allowed to make some assumption, it can be solved in O(1) time. To do it, the strictures the list points to must be copyable. The algorithm is as the following:
We have a list looking like: ... -> Node(i-1) -> Node(i) -> Node(i+1) -> ... and we need to delete Node(i).
Copy data (not pointer, the data itself) from Node(i+1) to Node(i), the list will look like: ... -> Node(i-1) -> Node(i+1) -> Node(i+1) -> ...
Copy the NEXT of second Node(i+1) into a temporary variable.
Now Delete the second Node(i+1), it doesn't require pointer to the previous node.
Pseudocode:
void delete_node(Node* pNode)
{
pNode->Data = pNode->Next->Data; // Assume that SData::operator=(SData&) exists.
Node* pTemp = pNode->Next->Next;
delete(pNode->Next);
pNode->Next = pTemp;
}
Mike.
Let's assume a list with the structure
A -> B -> C -> D
If you only had a pointer to B and wanted to delete it, you could do something like
tempList = B->next;
*B = *tempList;
free(tempList);
The list would then look like
A -> B -> D
but B would hold the old contents of C, effectively deleting what was in B. This won't work if some other piece of code is holding a pointer to C. It also won't work if you were trying to delete node D. If you want to do this kind of operation, you'll need to build the list with a dummy tail node that's not really used so you guarantee that no useful node will have a NULL next pointer. This also works better for lists where the amount of data stored in a node is small. A structure like
struct List { struct List *next; MyData *data; };
would be OK, but one where it's
struct HeavyList { struct HeavyList *next; char data[8192]; };
would be a bit burdensome.
Not possible.
There are hacks to mimic the deletion.
But none of then will actually delete the node the pointer is pointing to.
The popular solution of deleting the following node and copying its contents to the actual node to be deleted has side-effects if you have external pointers pointing to nodes in the list, in which case an external pointer pointing to the following node will become dangling.
I appreciate the ingenuity of this solution (deleting the next node), but it does not answer the problem's question. If this is the actual solution, the correct question should be "delete from the linked list the VALUE contained in a node on which the pointer is given". But of course, the correct question gives you a hint on solution.
The problem as it is formulated, is intended to confuse the person (which in fact has happened to me, especially because the interviewer did not even mention that the node is in the middle).
One approach would be to insert a null for the data. Whenever you traverse the list, you keep track of the previous node. If you find null data, you fix up the list, and go to the next node.
The best approach is still to copy the data of the next node into the node to be deleted, set the next pointer of the node to the next node's next pointer, and delete the next node.
The issues of external pointers pointing to the node to be deleted, while true, would also hold for the next node. Consider the following linked lists:
A->B->C->D->E->F and G->H->I->D->E->F
In case you have to delete node C (in the first linked list), by the approach mentioned, you will delete node D after copying the contents to node C. This will result in the following lists:
A->B->D->E->F and G->H->I->dangling pointer.
In case you delete the NODE C completely, the resulting lists will be:
A->B->D->E->F and G->H->I->D->E->F.
However, if you are to delete the node D, and you use the earlier approach, the issue of external pointers is still there.
The initial suggestion was to transform:
a -> b -> c
to:
a ->, c
If you keep the information around, say, a map from address of node to address of the next node then you can fix the chain the next time to traverse the list. If need to delete multiple items before the next traversal then you need to keep track of the order of deletes (i.e. a change list).
The standard solution is consider other data structures like a skip list.
Maybe do a soft delete? (i.e., set a "deleted" flag on the node) You can clean up the list later if you need to.
Not if you want to maintain the traversability of the list. You need to update the previous node to link to the next one.
How'd you end up in this situation, anyway? What are you trying to do that makes you ask this question?
You'll have to march down the list to find the previous node. That will make deleting in general O(n**2). If you are the only code doing deletes, you may do better in practice by caching the previous node, and starting your search there, but whether this helps depends on the pattern of deletes.
Given
A -> B -> C -> D
and a pointer to, say, item B, you would delete it by
1. free any memory belonging to members of B
2. copy the contents of C into B (this includes its "next" pointer)
3. delete the entire item C
Of course, you'll have to be careful about edge cases, such as working on lists of one item.
Now where there was B, you have C and the storage that used to be C is freed.
Considering below linked list
1 -> 2 -> 3 -> NULL
Pointer to node 2 is given say "ptr".
We can have pseudo-code which looks something like this:
struct node* temp = ptr->next;
ptr->data = temp->data;
ptr->next = temp->next;
free(temp);
yes, but you can't delink it. If you don't care about corrupting memory, go ahead ;-)
Yes, but your list will be broken after you remove it.
In this specific case, traverse the list again and get that pointer! In general, if you are asking this question, there probably exists a bug in what you are doing.
In order to get to the previous list item, you would need to traverse the list from the beginning until you find an entry with a next pointer that points to your current item. Then you'd have a pointer to each of the items that you'd have to modify to remove the current item from the list - simply set previous->next to current->next then delete current.
edit: Kimbo beat me to it by less than a minute!
You could do delayed delinking where you set nodes to be delinked out of the list with a flag and then delete them on the next proper traversal. Nodes set to be delinked would need to be properly handled by the code that crawls the list.
I suppose you could also just traverse the list again from the beginning until you find the thing that points to your item in the list. Hardly optimal, but at least a much better idea than delayed delinking.
In general, you should know the pointer to the item you just came from and you should be passing that around.
(Edit: Ick, with the time it took me to type out a fullish answer three gazillion people covered almost all the points I was going to mention. :()
The only sensible way to do this is to traverse the list with a couple of pointers until the leading one finds the node to be deleted, then update the next field using the trailing pointer.
If you want to delete random items from a list efficiently, it needs to be doubly linked. If you want take items from the head of the list and add them at the tail, however, you don't need to doubly link the whole list. Singly link the list but make the next field of the last item on the list point to the first item on the list. Then make the list "head" point to the tail item (not the head). It is then easy to add to the tail of the list or remove from the head.
You have the head of the list, right? You just traverse it.
Let's say that your list is pointed to by "head" and the node to delete it "del".
C style pseudo-code (dots would be -> in C):
prev = head
next = prev.link
while(next != null)
{
if(next == del)
{
prev.link = next.link;
free(del);
del = null;
return 0;
}
prev = next;
next = next.link;
}
return 1;
The following code will create a LL, n then ask the user to give the pointer to the node to be deleted. it will the print the list after deletion
It does the same thing as is done by copying the node after the node to be deleted, over the node to be deleted and then delete the next node of the node to be deleted.
i.e
a-b-c-d
copy c to b and free c so that result is
a-c-d
struct node
{
int data;
struct node *link;
};
void populate(struct node **,int);
void delete(struct node **);
void printlist(struct node **);
void populate(struct node **n,int num)
{
struct node *temp,*t;
if(*n==NULL)
{
t=*n;
t=malloc(sizeof(struct node));
t->data=num;
t->link=NULL;
*n=t;
}
else
{
t=*n;
temp=malloc(sizeof(struct node));
while(t->link!=NULL)
t=t->link;
temp->data=num;
temp->link=NULL;
t->link=temp;
}
}
void printlist(struct node **n)
{
struct node *t;
t=*n;
if(t==NULL)
printf("\nEmpty list");
while(t!=NULL)
{
printf("\n%d",t->data);
printf("\t%u address=",t);
t=t->link;
}
}
void delete(struct node **n)
{
struct node *temp,*t;
temp=*n;
temp->data=temp->link->data;
t=temp->link;
temp->link=temp->link->link;
free(t);
}
int main()
{
struct node *ty,*todelete;
ty=NULL;
populate(&ty,1);
populate(&ty,2);
populate(&ty,13);
populate(&ty,14);
populate(&ty,12);
populate(&ty,19);
printf("\nlist b4 delete\n");
printlist(&ty);
printf("\nEnter node pointer to delete the node====");
scanf("%u",&todelete);
delete(&todelete);
printf("\nlist after delete\n");
printlist(&ty);
return 0;
}
void delself(list *list)
{
/*if we got a pointer to itself how to remove it...*/
int n;
printf("Enter the num:");
scanf("%d",&n);
while(list->next!=NULL)
{
if(list->number==n) /*now pointer in node itself*/
{
list->number=list->next->number; /*copy all(name,rollnum,mark..)
data of next to current, disconnect its next*/
list->next=list->next->next;
}
list=list->next;
}
}
If you have a linked list A -> B -> C -> D and a pointer to node B. If you have to delete this node you can copy the contents of node C into B, node D into C and delete D. But we cannot delete the node as such in case of a singly linked list since if we do so, node A will also be lost. Though we can backtrack to A in case of doubly linked list.
Am I right?
void delself(list *list)
{
/*if we got a pointer to itself how to remove it...*/
int n;
printf("Enter the num:");
scanf("%d",&n);
while(list->next!=NULL)
{
if(list->number==n) /*now pointer in node itself*/
{
list->number=list->next->number;
/*copy all(name,rollnum,mark..) data of next to current, disconect its next*/
list->next=list->next->next;
}
list=list->next;
}
}
This is a piece of code I put together that does what the OP was asking for, and can even delete the last element in the list (not in the most elegant way, but it gets it done). Wrote it while learning how to use linked lists. Hope it helps.
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <string>
using namespace std;
struct node
{
int nodeID;
node *next;
};
void printList(node* p_nodeList, int removeID);
void removeNode(node* p_nodeList, int nodeID);
void removeLastNode(node* p_nodeList, int nodeID ,node* p_lastNode);
node* addNewNode(node* p_nodeList, int id)
{
node* p_node = new node;
p_node->nodeID = id;
p_node->next = p_nodeList;
return p_node;
}
int main()
{
node* p_nodeList = NULL;
int nodeID = 1;
int removeID;
int listLength;
cout << "Pick a list length: ";
cin >> listLength;
for (int i = 0; i < listLength; i++)
{
p_nodeList = addNewNode(p_nodeList, nodeID);
nodeID++;
}
cout << "Pick a node from 1 to " << listLength << " to remove: ";
cin >> removeID;
while (removeID <= 0 || removeID > listLength)
{
if (removeID == 0)
{
return 0;
}
cout << "Please pick a number from 1 to " << listLength << ": ";
cin >> removeID;
}
removeNode(p_nodeList, removeID);
printList(p_nodeList, removeID);
}
void printList(node* p_nodeList, int removeID)
{
node* p_currentNode = p_nodeList;
if (p_currentNode != NULL)
{
p_currentNode = p_currentNode->next;
printList(p_currentNode, removeID);
if (removeID != 1)
{
if (p_nodeList->nodeID != 1)
{
cout << ", ";
}
cout << p_nodeList->nodeID;
}
else
{
if (p_nodeList->nodeID !=2)
{
cout << ", ";
}
cout << p_nodeList->nodeID;
}
}
}
void removeNode(node* p_nodeList, int nodeID)
{
node* p_currentNode = p_nodeList;
if (p_currentNode->nodeID == nodeID)
{
if(p_currentNode->next != NULL)
{
p_currentNode->nodeID = p_currentNode->next->nodeID;
node* p_temp = p_currentNode->next->next;
delete(p_currentNode->next);
p_currentNode->next = p_temp;
}
else
{
delete(p_currentNode);
}
}
else if(p_currentNode->next->next == NULL)
{
removeLastNode(p_currentNode->next, nodeID, p_currentNode);
}
else
{
removeNode(p_currentNode->next, nodeID);
}
}
void removeLastNode(node* p_nodeList, int nodeID ,node* p_lastNode)
{
node* p_currentNode = p_nodeList;
p_lastNode->next = NULL;
delete (p_currentNode);
}
Void deleteMidddle(Node* head)
{
Node* slow_ptr = head;
Node* fast_ptr = head;
Node* tmp = head;
while(slow_ptr->next != NULL && fast_ptr->next != NULL)
{
tmp = slow_ptr;
slow_ptr = slow_ptr->next;
fast_ptr = fast_ptr->next->next;
}
tmp->next = slow_ptr->next;
free(slow_ptr);
enter code here
}

Resources