Delete a node from a linked list [duplicate] - c

This question already has answers here:
Deleting a middle node from a single linked list when pointer to the previous node is not available
(24 answers)
Closed 8 years ago.
what i want to do is make a function that will get a list as an input and a number and will delete the node of that list that equals to that particular number. So if i have a linked list lets say:
struct num // list 1
{
char *val;
struct num *next;
};
and i have added 4 items to that list, i want to be able to delete the third item and get back the new list with now 3 items. Everything i have tried till now though wont work, i think because i am not linking the remaining items correctly after i delete one of them.
Since you insist here is what i have till now
struct num1 *temp;
temp = head;
struct num1* deletend(int del){
for ( int i = 0; i < listSize; i++)
{
if (i == del){
free(temp);
}
temp = temp->next;
}
return temp;
}

The following code solves the purpose :
typedef struct num numNode; // typedef to escape repeated struct num
numNode* delete_item(numNode* startNode, int position)
{
int pos = 0;
numNode* current = NULL;
numNode* prev = NULL;
if ((start == NULL) || (position == 0)) // if empty list or 0th item deletion, return the list as it is
return start;
else if (position == 1) // if delete first item,
{
current = start; // this node to be deleted
start = start->next; // Set start to the next item
free current;
current = NULL; // delete the node
return start;
}
else
{
prev = start; // this will mark the previous node
current = prev->next; // this will mark the current node
pos = 2; // position 0, 1 taken care of
}
while ((current != NULL))
{
if (pos == position)
{
prev->next = current->next;
free current;
current = NULL;
break;
}
pos++;
}
return start;
}

You need to keep the pointer to the previous member to the one deleted. Then replace the pointer in the previous to the deleted member with the pointer to the next member that was in the deleted member.

Related

Updating linked-list by pointer inside a function

I'm missing with linked-list and trying to make a function which gonna take of all the odd numbers out of the link and make a new linked-list with them.
The point is that I dont understand how to update the original list by pointer to the function, actually what I made so far is making a new list with the odd numbers but I dont really understand how to "delete" them from the original list and link all the rest togther, then send it back to the main.
Node *build_odd_list(Node *oldlst, Node *newlst) {
Node *temp, *curheadNew;
temp = (Node*)malloc(sizeof(Node));
if (oldlst->value % 2 != 0) {
temp->next = NULL;
temp->value = oldlst->value;
newlst = temp;
curheadNew = newlst;
oldlst = oldlst->next;
printf("Passed %d\n", curheadNew->value);
}
else {
oldlst = oldlst->next;
}
while (oldlst) {
if (oldlst->value % 2 != 0) {
temp = (Node*)malloc(sizeof(Node));
temp->value = oldlst->value;
temp->next = NULL;
curheadNew->next = temp;
curheadNew = curheadNew->next;
oldlst = oldlst->next;
printf("Passed %d\n", curheadNew->value);
}
else {
oldlst = oldlst->next;
}
}
return newlst;
}
Thanks a lot!
Since you need to return a new list containing the odd numbers, and modify the original list due to removal of the odd numbers, you need to pass two values back to the caller: a pointer to the first element of the updated original list, and a pointer to the first element of the "odd numbers" list.
Since you need to pass the original list to the function anyway, the simplest option for the function is to:
pass a pointer to a pointer to the first element of the original list;
modify the original list via the pointer;
return a pointer to the first element of the "odd numbers" list extracted from the original list.
There is no need to allocate any new elements for the "odd numbers" list as the odd number elements can be moved from one list to the other.
It is worth learning the "pointer to a pointer" trick as it is a common way of manipulating list pointers.
Here is an example program to illustrate the above method. Pay particular attention to the extract_odd_list() function and the call to that function from main().
#include <stdio.h>
#include <stdlib.h>
typedef struct _Node {
int value;
struct _Node *next;
} Node;
/* Move odd numbers in *list to returned list. */
Node *extract_odd_list(Node **list) {
Node *oddstart = NULL; /* start of returned list */
Node **oddend = &oddstart; /* pointer to final link of returned list */
while (*list) {
if ((*list)->value % 2 != 0) {
/* Current element of original *list is odd. */
/* Move original *list element to end of returned list. */
*oddend = *list;
/* Bypass moved element in original list. */
*list = (*list)->next;
/* Update pointer to final link of returned list. */
oddend = &(*oddend)->next;
}
else {
/* Current element of original *list is even. */
/* Skip to next element of original *list. */
list = &(*list)->next;
}
}
/* Terminate the returned list. */
*oddend = NULL;
/* And return it. */
return oddstart;
}
void *printlist(Node *list) {
while (list) {
printf(" %d", list->value);
list = list->next;
}
}
int main(void) {
int i;
Node *list = NULL;
Node *end = NULL;
Node *oddlist;
Node *temp;
/* Construct a list containing odd and even numbers. */
for (i = 1; i <= 10; i++) {
temp = malloc(sizeof(*temp));
temp->value = i;
if (end == NULL) {
list = temp;
}
else {
end->next = temp;
}
end = temp;
}
end->next = NULL;
printf("Original list:");
printlist(list);
printf("\n");
/* Move the "odd number" elements from the original list to a new list. */
oddlist = extract_odd_list(&list);
printf("Updated list:");
printlist(list);
printf("\n");
printf("Odd list:");
printlist(oddlist);
printf("\n");
return 0;
}

C Program - Removing duplicates from LinkedList

I am trying out on removing duplicates from a linkedlist. The user will insert one value and then, the program will check if the user's input and value in the linkedlist are the same. If it's similar, it will remove and leave only one in the linkedlist. For e.g. linkedlist=10 100. user=10. outcome=10 100 and not 10 10 100.
int insertSorted(LinkedList *ll, int item)
{
ListNode *cur = ll->head;
int size = ll->size;
int i;
for (i = 0; i <= size; i++)
{
if ((size - i) == 0 || item < cur->item)
{
insertNode(ll, i, item); // function to insert the value into Linkedlist
return i;
}
cur = cur->next;
}
ListNode *current = ll->head;
while (current->next != NULL)
{
if (current->item == current->next->item)
{
ListNode *nextNext = current->next->next;
free(current->next);
current->next = nextNext;
}
else
{
current = current->next; // only advance if no deletion
}
}
return -1;
}
When you insert the new node (the value 10 in your example), you then return i;, making the rest of the code, which I suppose checks for duplicates not to execute.
If you always return after you insert, you don't reach the code that deletes the duplicate. I think you need to break instead.
Also, where do you modify the size of the linked-list when you delete an element?
Should be reduced by 1 if I understand correctly.
In addition, since you clean duplicates after every insertion, you don't need the conditional advancement in the deleting loop

c bubblesort a link list

trying to get a function to run that will bubble sort a link list from smallest to largest number. I don't want the data to be moved around in the link list instead have the pointers be pointing elsewhere in case each link needs to hold a lot of data.
In each link I have a INT arrivalTime field that will house a integer value. THis number determines where the link should be in the list.
My program seems to hang at the moment, I'd appreciate if anyone could fix it up, Thanks
bubble sort function
void bubbleSort(struct order *start)
{
int swapped, i;
processData *current = start;
processData *temp;
struct order *lptr = NULL;
/* Checking for empty list */
if (current == NULL)
printf("null \n");
do
{
swapped = 0;
current = start;
while (current->next != lptr)
{
if (current->arrivalTime > current->next->arrivalTime)
{
temp = current;
current = current->next;
current->next = temp;
swapped = 1;
}
current = current->next;
}
lptr = current;
}
while (swapped);
}
structure of link list
struct order
{
int name;
int arrivalTime;
int quanta;
struct order * next;
};
typedef struct order processData;
Swapping two adjacent items in a singly-linked-list requires that you change three next pointers.
If the order is A --> B --> C --> D and you swap B with C to get A --> C --> B --> D then
A->next needs to point to C instead of B
B->next needs to point to D instead of C
C->next needs to point to B instead of D
This is a very slow thing you're trying to do - see this paper on comparing ways to sort a linked list.
Currently, your algorithm will never terminate because in your while loop, you set lptr = current, but then test whether current->next == lptr. This will never return true unless one of your list members points to itself.
If you do have a definite use case to bubble sort the linked list, consider this: The purpose of a linked list is that you access it by working sequentially from the list head to the item you want. If your initial list head is not the smallest or the largest and you're only changing pointers, you need to keep track of where the head of the list is.
I did think of a way to do it loosely based on yours, see below. Sorry it's a bit messy - I'm not a C expert (hope the memory allocation is OK...) and I'm sure there are optimisations. In particular I'm sure there are better ways to pass the headOfList pointer back to the main algorithm. I've tested it for a number of 100 member lists of structs with some negative numbers. I've left the code to generate them with random arrival times in main() so you can just paste this in where your old code was and run it.
processData *bubbleSort(processData *start)
{
int swapped;
processData *current = start;
processData *lheadptr = start;
processData *previous = NULL;
processData *oldPrevButBigger;
processData *oldAfterThisPair;
/* Checking for empty list */
if (current == NULL)
{
printf("null \n");
return NULL;
}
do
{
swapped = 0;
current = lheadptr;
previous = NULL;
while (current->next) //Stop when current->next is null (i.e. end of list)
{
if (current->arrivalTime > current->next->arrivalTime)
{
oldPrevButBigger = current;
oldAfterThisPair = current->next->next;
current = current->next;
current->next = oldPrevButBigger;
current->next->next = oldAfterThisPair;
if (!previous)
{
//If no previous, this was the head of the list, so need to update
lheadptr = current;
}
else
{
// If there is a "previous", then we're not at head of list, so need
// to update that pointer too
previous->next = current;
}
swapped = 1;
}
previous = current;
current = current->next;
}
}
while (swapped);
return lheadptr;
}
int main()
{
srand(time(NULL));
int NUM = 100;
processData* pointToLast = NULL;
int i;
processData orders[NUM];
//Generate a list with random arrival times (last member of the list generated first
for (i = 0; i < NUM; i++ )
{
orders[i].name = i;
orders[i].arrivalTime = rand()-1000000000;
orders[i].quanta = 500;
orders[i].next = pointToLast;
pointToLast = &orders[i];
}
printf("List before\n");
printf("===========\n");
for (i=0; i < NUM; i++)
{
printf("%i;%i;%i\n", pointToLast->name, pointToLast->arrivalTime, pointToLast->quanta);
pointToLast = pointToLast->next;
}
processData* newListHead = bubbleSort(&orders[NUM-1]);
printf("List after\n");
printf("===========\n");
for (i=0; i < NUM; i++)
{
printf("%i;%i;%i\n", newListHead->name, newListHead->arrivalTime, newListHead->quanta);
newListHead = newListHead->next;
}
return 0;
}

Remove an element from linked list at a given position

I have a simple question about removing an element from a linked list. The only difference between what I am trying to accomplish and what I have seen in code online is that I am trying to remove an element, given a position, rather than given the actual element that needs to be removed.
Any help is appreciated.
You can do that, Here is the sample program which can delete any node based on the index you are supplying as an argumenT.
start -> Pointing to the first node
traverse ->pointing to the node which has to be deleted
traverseNext->pointing to the previous of node which has to be deleted.
And the code looks like below.
#include <iostream>
struct myList
{
int data;
struct myList *next;
};
struct myList *start=NULL;
//this method removes a node from the position index
void remove(int index)
{
myList *traverse = start;
myList *traverseNext = NULL;
int i = 1;
while(i<(index-1))
{
traverse = traverse->next;
i++;
}
traverseNext = traverse;
traverse = traverse->next;
if(traverse->next == NULL)
{
delete traverse;
traverseNext->next = NULL;
traverse = NULL;
return;
}
else
{
traverseNext->next = traverse->next;
delete traverse;
traverse = NULL;
return;
}
}
int main(void)
{
myList *node1;
myList *node2;
myList *node3;
node1 = new myList;
node2 = new myList; //Created 3 nodes of type myList
node3 = new myList;
node1->data = 10;
node1->next = node2;
node2->data = 20;
node2->next = node3;
node3->data = 30;
node3->next = NULL;
start = node1; //start is pointing to node1
remove(2); //removing the node 2, so the output will be 10 30
while(start) //iterating through all the nodes from start, since start
{ //is pointing to the first node.
std::cout<<start->data<<" ";
start = start->next;
}
}
Deleting a node in a linked list to which the pointer is given can be done in O(1) time. We don't have to do traversal.
I am assuming that by position you meant the pointer to the node is given:
Lets say node is the element that needs to be removed.
node->data = node->next->data;
Node* temp = node->next;
node->next = node->next->next;
free(temp);
But if the position means the nth element in the list, the only way would be to traverse up to the (n-1)th element and delete the next element by (regular deletion in a linked list):
Node* temp = previous->next;
previous->next = temp->next;
free(temp);
This is all assuming that the linked-list is a pointer based linked-list
This is simple:
1) Locate the Nth item by iterating through the list, additionally using a counter to keep track of which node you're one.
2) Remove that node, as you would any other linked list.
Seek the list until you find the nth element (use a counter), and then update the previous node's next pointer to point to the one after the one you're currently at (effectively removing it). Adjust the previous pointer if you're using them, too.
If you want to remove multiple items you can first iterate over the list and then collect all items that you want to remove to another list. Then simply call 'removeAll' passing in the collected list.
#include <stdio.h>
#include <stdlib.h>
typedef struct element{
int num;
struct element * next;
} element;
void delNth(element **header, int pos){//pos : zero origin
element *prev, *tmp;
int i;
if(header == NULL || *header == NULL || pos < 0) return ;
if(pos == 0){
tmp = (*header)->next;
free(*header);
*header = tmp;
} else {
prev = *header;
tmp = (*header)->next;
for(i=1;i<pos;++i){
prev = tmp;
tmp = tmp->next;
if(tmp == NULL) return ;//or rise error
}
prev->next = tmp->next;
free(tmp);
}
}
void drop(element *header){
if(header){
drop(header->next);
free(header);
}
}
void printList(element *header){
while (header!=NULL){
printf("%d ",header->num);
header=header->next;
}
printf("\n");
}
int main(int argc, char **argv){
int pos = atoi(argv[1]);
element *a;
element *b;
element *c;
a=malloc(sizeof(element));
b=malloc(sizeof(element));
c=malloc(sizeof(element));
a->num=5;
b->num=6;
c->num=7;
a->next=b;
b->next=c;
c->next=NULL;
printList(a);
delNth(&a, pos);
printList(a);
drop(a);
return 0;
}
/* execute result
>a 0
5 6 7
6 7
>a 1
5 6 7
5 7
>a 2
5 6 7
5 6
>a 3
5 6 7
5 6 7
*/

Splitting a linked list

Why are the split lists always empty in this program? (It is derived from the code on the Wikipedia page on Linked Lists.)
/*
Example program from wikipedia linked list article
Modified to find nth node and to split the list
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct ns
{
int data;
struct ns *next; /* pointer to next element in list */
} node;
node *list_add(node **p, int i)
{
node *n = (node *)malloc(sizeof(node));
if (n == NULL)
return NULL;
n->next = *p; //* the previous element (*p) now becomes the "next" element */
*p = n; //* add new empty element to the front (head) of the list */
n->data = i;
return *p;
}
void list_print(node *n)
{
int i=0;
if (n == NULL)
{
printf("list is empty\n");
}
while (n != NULL)
{
printf("Value at node #%d = %d\n", i, n->data);
n = n->next;
i++;
}
}
node *list_nth(node *head, int index) {
node *current = head;
node *temp=NULL;
int count = 0; // the index of the node we're currently looking at
while (current != NULL) {
if (count == index)
temp = current;
count++;
current = current->next;
}
return temp;
}
/*
This function is to split a linked list:
Return a list with nodes starting from index 'int ind' and
step the index by 'int step' until the end of list.
*/
node *list_split(node *head, int ind, int step) {
node *current = head;
node *temp=NULL;
int count = ind; // the index of the node we're currently looking at
temp = list_nth(current, ind);
while (current != NULL) {
count = count+step;
temp->next = list_nth(head, count);
current = current->next;
}
return temp; /* return the final stepped list */
}
int main(void)
{
node *n = NULL, *list1=NULL, *list2=NULL, *list3=NULL, *list4=NULL;
int i;
/* List with 30 nodes */
for(i=0;i<=30;i++){
list_add(&n, i);
}
list_print(n);
/* Get 1th, 5th, 9th, 13th, 18th ... nodes of n etc */
list1 = list_split(n, 1, 4);
list_print(list1);
list2 = list_split(n, 2, 4); /* 2, 6, 10, 14 etc */
list_print(list2);
list3 = list_split(n, 3, 4); /* 3, 7, 11, 15 etc */
list_print(list3);
list3 = list_split(n, 4, 4); /* 4, 8, 12, 16 etc */
list_print(list4);
getch();
return 0;
}
temp = list_nth(current, ind);
while (current != NULL) {
count = count+step;
temp->next = list_nth(head, count);
current = current->next;
}
You are finding the correct item to begin the split at, but look at what happens to temp from then on ... you only ever assign to temp->next.
You need to keep track of both the head of your split list and the tail where you are inserting new items.
The program, actually, has more than one problem.
Indexes are not a native way to address linked list content. Normally, pointers to nodes or iterators (which are disguised pointers to nodes) are used. With indexes, accessing a node has linear complexity (O(n)) instead of constant O(1).
Note that list_nth returns a pointer to a "live" node within a list, not a copy. By assigning to temp->next in list_split, you are rewiring the original list instead of creating a new one (but maybe it's intentional?)
Within list_split, temp is never advanced, so the loop just keeps attaching nodes to the head instead of to the tail.
Due to use of list_nth for finding nodes by iterating through the whole list from the beginning, list_split has quadratic time (O(n**2)) instead of linear time. It's better to rewrite the function to iterate through the list once and copy (or re-attach) required nodes as it passes them, instead of calling list_nth. Or, you can write current = list_nth(current, step).
[EDIT] Forgot to mention. Since you are rewiring the original list, writing list_nth(head, count) is incorrect: it will be travelling the "short-cirquited" list, not the unmodified one.
I also notice that it looks like you are skipping the first record in the list when you are calculating list_nth. Remember is C we normally start counting at zero.
Draw out a Linked List diagram and follow your logic:
[0]->[1]->[2]->[3]->[4]->[5]->[6]->[7]->[8]->[9]->...->[10]->[NULL]
Your description of what list_split is supposed to return is pretty clear, but it's not clear what is supposed to happen, if anything, to the original list. Assuming it's not supposed to change:
node *list_split(node *head, int ind, int step) {
node *current = head;
node *newlist=NULL;
node **end = &newlist;
node *temp = list_nth(current, ind);
while (temp != NULL) {
*end = (node *)malloc(sizeof(node));
if (*end == NULL) return NULL;
(*end)->data = temp->data;
end = &((*end)->next);
temp = list_nth(temp, step);
}
return newlist; /* return the final stepped list */
}
(You probably want to factor a list_insert routine out of that that inserts a new
node at a given location. list_add isn't very useful since it always adds to the
beginning of the list.)

Resources