Delete from double Linked List - c

I'm trying to delete a node from a doubly linked list but I have a problem
and this problem is when the node is the first or in the middle it prints 0 instead and it's not really deleted , but it works well when it's the last node in the list and here is the code:
dList* del(dList*ptr, int x)
{
dList *itr = NULL;
for( itr = ptr; itr != NULL; itr = itr -> next)
{
// if the element is the first in the list
if(itr -> value == x && itr -> prev == NULL)
{
itr -> next -> prev = NULL;
ptr = itr -> next;
free(itr);
}
// if the element is the last in the list
else if(itr -> value == x && itr -> next == NULL)
{
itr -> prev -> next = NULL;
free(itr);
}
// if its in the middle
else if(itr -> value == x){
(itr -> prev) -> next = itr -> next;
(itr -> next) -> prev = itr -> prev;
free(itr);
}
}
return ptr;
}
thanks in advance!

This loop
for( itr = ptr; itr != NULL; itr = itr -> next)
{
// if the element is the first in the list
if(itr -> value == x && itr -> prev == NULL)
{
itr -> next -> prev = NULL;
ptr = itr -> next;
free(itr);
}
// ...
has undefined behavior.
For example in the third expression of the for loop
itr = itr -> next
you are using already deleted pointer
free(itr);
If the list for example has only one node then itr->next is equal to NULL. So again this statement
itr -> next -> prev = NULL;
also invokes undefined behavior.
The function can look much simpler if to pass the head node by reference through pointer to it.
Also a more useful return value is the number of the deleted nodes in the list.
The function definition can look the following way
size_t del( dList **ptr, int value )
{
size_t n = 0;
while ( *ptr != NULL )
{
if ( ( *ptr )->value == value )
{
dList *tmp = *ptr;
*ptr = ( *ptr )->next;
if ( *ptr ) ( *ptr )->prev = tmp->prev;
free( tmp );
++n;
}
else
{
ptr = &( *ptr )->next;
}
}
return n;
}
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
typedef struct dList
{
int value;
struct dList *prev;
struct dList *next;
} dList;
size_t del( dList **ptr, int value )
{
size_t n = 0;
while ( *ptr != NULL )
{
if ( ( *ptr )->value == value )
{
dList *tmp = *ptr;
*ptr = ( *ptr )->next;
if ( *ptr ) ( *ptr )->prev = tmp->prev;
free( tmp );
++n;
}
else
{
ptr = &( *ptr )->next;
}
}
return n;
}
int push_front( dList **head, int value )
{
dList *new_node = malloc( sizeof( dList ) );
int success = new_node != NULL;
if ( success )
{
new_node->prev = NULL;
new_node->value = value;
new_node->next = *head;
if ( *head ) ( *head )->prev = new_node;
*head = new_node;
}
return success;
}
void out( dList *head )
{
for ( ; head != NULL; head = head->next )
{
printf( "%d --> ", head->value );
}
puts( "NULL" );
}
int main(void)
{
dList *head = NULL;
push_front( &head, 1 );
push_front( &head, 2 );
push_front( &head, 1 );
out( head );
size_t n = del( &head, 1 );
printf( "%zu nodes are deleted.\n", n );
out( head );
n = del( &head, 2 );
printf( "%zu nodes are deleted.\n", n );
out( head );
return 0;
}
Its output is
1 --> 2 --> 1 --> NULL
2 nodes are deleted.
2 --> NULL
1 nodes are deleted.
NULL

Related

Partition a Linked List (C)

The problem asks us to split a Linked List based on a pivot value
(1->2->4->6->3->5 pivot = 5 ) => ( 1->2->4->3->5->6)
My Solution to the problem was to create 3 new linked list and split based on the pivot value. However I am not able to concatenate the 3 linked list together and let head point to the new concatenated linked list. Please guide me through on how I can concatenate the 3 linked list and let head point to the concatenated linked list.
void triPartition(ListNode** head, int pivot){
ListNode *cur;
ListNode ** Small = NULL;
ListNode ** Equal = NULL;
ListNode ** Large = NULL;
int Scount = 0 , Ecount = 0 , Lcount = 0;
cur = (*head);
if(cur == NULL)
{
return 0;
}
if(cur->next == NULL)
{
return 0;
}
while(cur != NULL)
{
if(cur->item == pivot)
{
insertNode(&Equal, Ecount, cur->item);
Ecount++;
}
else if(cur->item < pivot)
{
insertNode(&Small, Scount, cur->item);
Scount++;
}
else
{
insertNode(&Large, Lcount, cur->item);
Lcount++;
}
cur = cur->next;
}
This part of my solution does not work
*head = Small;
while((*Small)->next!=NULL)
{
Small = (*Small)->next;
}
(*Small)->next = Equal;
while((*Equal)->next!=NULL)
{
Equal = (*Equal)->next;
}
(*Equal)->next = Large;
}
It seems that no professional programmer are going tp help you. So we beginners should help each other ourselves.:)
Using your approach to the function implementation by means of creating at first three separate lists and then combining them in one list I can suggest the following function definition shown in the demonstration program below.
#include <stdio.h>
#include <stdlib.h>
typedef struct ListNode
{
int item;
struct ListNode *next;
} ListNode;
void clear( ListNode **head )
{
while (*head)
{
ListNode *current = *head;
*head = ( *head )->next;
free( current );
}
}
size_t assign( ListNode **head, const int a[], size_t n )
{
clear( head );
size_t i = 0;
for ( ; i != n && ( *head = malloc( sizeof( ListNode ) ) ) != NULL; i++)
{
( *head )->item = a[i];
( *head )->next = NULL;
head = &( *head )->next;
}
return i;
}
FILE *display( const ListNode * const head, FILE *fp )
{
for ( const ListNode *current = head; current != NULL; current = current->next)
{
fprintf( fp, "%d -> ", current->item );
}
fputs( "null", fp);
return fp;
}
void triPartition( ListNode **head, int pivot )
{
ListNode * small = NULL;
ListNode * equal = NULL;
ListNode * large = NULL;
ListNode ** small_ptr = &small;
ListNode ** equal_ptr = &equal;
ListNode ** large_ptr = &large;
for ( ListNode *current = *head; current != NULL; )
{
ListNode *tmp = current;
current = current->next;
tmp->next = NULL;
if ( tmp->item < pivot )
{
*small_ptr = tmp;
small_ptr = &( *small_ptr )->next;
}
else if ( pivot < tmp->item )
{
*large_ptr = tmp;
large_ptr = &( *large_ptr )->next;
}
else
{
*equal_ptr = tmp;
equal_ptr = &( *equal_ptr )->next;
}
}
*equal_ptr = large;
*small_ptr = equal;
*head = small;
}
int main( void )
{
int a[] = { 1, 2, 4, 6, 3, 5 };
ListNode *head = NULL;
assign( &head, a, sizeof( a ) / sizeof( *a ) );
fputc( '\n', display( head, stdout ) );
triPartition( &head, 5 );
fputc( '\n', display( head, stdout ) );
clear( &head );
}
The program output is
1 -> 2 -> 4 -> 6 -> 3 -> 5 -> null
1 -> 2 -> 4 -> 3 -> 5 -> 6 -> null

A C function that inserts number into a linked list in ascending order

This is my function:
void IntListInsertInOrder (IntList L, int v)
{
struct IntListNode *n = newIntListNode (v);
if (L->first == NULL) { //case a, empty list
L->first = L->last = n;
L->size ++;
return;
}
else if (v <= L->first->data) { // case b, smallest value
n->next = L->first;
L->first = n;
}
else if (v >= L->last->data) { // case c, largest value
L->last->next = n;
L->last = n;
}
else if (v > L->first->data && v <= L->first->next->data) { // case d, second-smallest value
n->next = L->first->next;
L->first->next = n;
}
else { //case f, value in the middle
struct IntListNode *curr = L->first;
while (curr->next->data < v) {
curr = curr->next;
}
n->next = curr->next;
curr->next = n;
}
L->size ++;
return;
}
when i put random lists of 10 numbers into it, 3/10 sorted correctly. the errors seem to be in the last part but it looks exactly like solutions i found online.
OK I figured it out. I forgot to add&& curr-> != NULLin the condition of the last while loop. After I added that all the test cases passed.
Your function is too complicated, has many if conditions and as a result it is error-prone and unreadable.
You did not show the list definition but I can guess that you have a two-sided singly-linked list because nowhere in the code there is a reference to a data member named prev.
Here is a demonstrative program that shows how the function can be simply defined.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct Node
{
int data;
struct Node *next;
} Node;
typedef struct List
{
Node *head;
Node *tail;
size_t size;
} List;
int insert_in_order( List *list, int data )
{
Node *new_node = malloc( sizeof( Node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
Node **current = &list->head;
while ( *current != NULL && !( data < ( *current )->data ) )
{
current = &( *current )->next;
}
new_node->next = *current;
if ( *current == NULL )
{
list->tail = new_node;
}
*current = new_node;
++list->size;
}
return success;
}
void clear( List *list )
{
while ( list->head != NULL )
{
Node *current = list->head;
list->head = list->head->next;
free( current );
}
}
void display( const List *list )
{
printf( "There are %zu nodes in the list\n", list->size );
printf( "They are: " );
for ( const Node *current = list->head; current != NULL; current = current->next )
{
printf( "%d -> ", current->data );
}
puts( "null" );
}
int main(void)
{
List list = { .head = NULL, .tail = NULL, .size = 0 };
srand( ( unsigned int )time( NULL ) );
const size_t N = 10;
for ( size_t i = 0; i < N; i++ )
{
insert_in_order( &list, rand() % ( int )N );
}
display( &list );
clear( &list );
return 0;
}
The program output might look like
There are 10 nodes in the list
They are: 1 -> 2 -> 3 -> 3 -> 6 -> 6 -> 7 -> 8 -> 8 -> 9 -> null

Having a hard time creating a function for lists in C

I am trying to create a function delz() which deletes a given number from the end of the list, I tried recursively and with a while loop and I can't figure it out.
Example: [ 3 | next ] - [ 4 | next ] - [ 3 | next ] - [ 7 | next ] -----> [ 3 | next ] - [ 4 | next ] - [ 7 | next ]
list delz (int val, list l) {
if(l == NULL)
return NULL;
else {
list head = l;
list tmp = l;
list tail;
list temp;
while(l != NULL){
if(l->value == val) {
list tail = l->next;
head->next = tail;
}
temp = head;
head = tmp;
l = l->next;
}
return head;
}
}
typedef struct node {
int value;
struct node *next;
} node, *list;
The function will be simpler if to pass to the function the pointer to the head node by reference.
Here is a demonstrative program. I used my own singly-linked list definition because you did not show your own. Also it is a bad idea to introduce a typedef for a pointer type.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int val;
struct Node *next;
};
void assign( struct Node **head, const int a[], size_t n )
{
if ( *head )
{
struct Node *tmp = *head;
*head = ( *head )->next;
free( tmp );
}
for ( size_t i = 0; i < n; i++ )
{
*head = malloc( sizeof( struct Node ) );
( *head )->val = a[i];
( *head )->next = NULL;
head = &( *head )->next;
}
}
void display( const struct Node *head )
{
for ( ; head != NULL; head = head->next )
{
printf( "%d -> ", head->val );
}
puts( "null" );
}
int remove_last( struct Node **head, int val )
{
struct Node **target = NULL;
for ( ; *head != NULL; head = &( *head )->next )
{
if ( ( *head )->val == val ) target = head;
}
int success = target != NULL;
if ( success )
{
struct Node *tmp = *target;
*target = ( *target )->next;
free( tmp );
}
return success;
}
int main(void)
{
int a[] = { 3, 4, 3, 7 };
const size_t N = sizeof( a ) / sizeof( *a );
struct Node *head = NULL;
assign( &head, a, N );
display( head );
int val = 3;
if ( remove_last( &head, val ) )
{
printf( "The last node with the value %d is removed.\n", val );
}
display( head );
return 0;
}
The program output is
3 -> 4 -> 3 -> 7 -> null
The last node with the value 3 is removed.
3 -> 4 -> 7 -> null

How to delete multiple occurrences of multiple variables in a linked list in c

I am a beginner in c programming and i have been trying for several days to solve the following question:
how to remove numbers that appear at least 3 times in the following list:
3→3→1→2→4→3→5→3→5→4
which makes the result:
1→2→4→5→5→4.
Now i know how to delete multiple occurrences of "one" key in a linked list, for example deleting all occurrences of "1" in the linked list, but can't seem to understand how to delete multiple occurrences of multiple variables. It's just killing me. I would really appreciate it if anyone could help. thanks in advance.
It seems nobody hurries to help you.:)
It is simpler to write the function if to pass the pointer head to the function by reference.
Here is a demonstrative program that shows how the function can be implemented.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
int insert( struct Node **head, int data )
{
struct Node *node = malloc( sizeof( struct Node ) );
int success = node != NULL;
if ( success )
{
node->data = data;
node->next = *head;
*head = node;
}
return success;
}
void out( struct Node *head )
{
for ( ; head != NULL; head = head->next )
{
printf( "%d -> ", head->data );
}
puts( "null" );
}
void remove_repetitive( struct Node **head )
{
const size_t LIMIT = 3;
while ( *head != NULL )
{
size_t count = 1;
int data = ( *head )->data;
for ( struct Node *node = ( *head )->next;
count < LIMIT && node != NULL; node = node->next )
{
if ( node->data == data ) ++count;
}
if ( count == LIMIT )
{
for ( struct Node **node = head; *node != NULL; )
{
if ( ( *node )->data == data )
{
struct Node *tmp = *node;
*node = ( *node )->next;
free( tmp );
}
else
{
node = &( *node )->next;
}
}
}
else
{
head = &( *head )->next;
}
}
}
int main(void)
{
struct Node *head = NULL;
int a[] = { 4, 5, 3, 5, 3, 4, 2, 1, 3, 3 };
const size_t N = sizeof( a ) / sizeof( *a );
for ( size_t i = 0; i < N; i++ )
{
insert( &head, a[i] );
}
out( head );
remove_repetitive( &head );
out( head );
return 0;
}
The program output is
3 -> 3 -> 1 -> 2 -> 4 -> 3 -> 5 -> 3 -> 5 -> 4 -> null
1 -> 2 -> 4 -> 5 -> 5 -> 4 -> null
The function remove_repetitive can be splitted out into two functions as it is shown below.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
int insert( struct Node **head, int data )
{
struct Node *node = malloc( sizeof( struct Node ) );
int success = node != NULL;
if ( success )
{
node->data = data;
node->next = *head;
*head = node;
}
return success;
}
void out( struct Node *head )
{
for ( ; head != NULL; head = head->next )
{
printf( "%d -> ", head->data );
}
puts( "null" );
}
void remove_all( struct Node **head, int data )
{
while ( *head != NULL )
{
if ( ( *head )->data == data )
{
struct Node *tmp = *head;
*head = ( *head )->next;
free( tmp );
}
else
{
head = &( *head )->next;
}
}
}
void remove_repetitive( struct Node **head )
{
const size_t LIMIT = 3;
while ( *head != NULL )
{
size_t count = 1;
int data = ( *head )->data;
for ( struct Node *node = ( *head )->next;
count < LIMIT && node != NULL; node = node->next )
{
if ( node->data == data ) ++count;
}
if ( count == LIMIT )
{
remove_all( head, data );
}
else
{
head = &( *head )->next;
}
}
}
int main(void)
{
struct Node *head = NULL;
int a[] = { 4, 5, 3, 5, 3, 4, 2, 1, 3, 3 };
const size_t N = sizeof( a ) / sizeof( *a );
for ( size_t i = 0; i < N; i++ )
{
insert( &head, a[i] );
}
out( head );
remove_repetitive( &head );
out( head );
return 0;
}
The program output is the same as shown above.

Merge Sorted Linked Lists with head node and without new nodes (void function)

I am writing a void function void merged_lists (cell * l1, cell * l2, cell * l3); who receives two linked lists, headed by l1 and l2, whose content is ordered in non-decreasing order, and
generate a new list headed by l3 that contains the elements of l1 and l2 ordered.
If the list headed by l1 is l1 -> 1 -> 7 -> 9 -> 10 -> NULL and headed by l2 is l2 -> 2 -> 3 -> 8 -> NULL, for example, the output must be l3 -> 1 -> 2 -> 3 -> 7 -> 8 -> 9 -> 10 -> NULL
This is a problem with a known resolution, but I'm trying to solve it without allocate any new cells in function, just manipulating the pointers from nodes of l to be in l1 and l2.
My approach:
typedef struct cell {
int data;
struct cell *next;
} cell;
void merged_lists (cell * l1, cell * l2, cell * l3){
if(l1->next == NULL)
l3 = l2->next;
if(l2->next == NULL)
l3 = l1->next;
if(l1->next->data <= l2->next->data)
l3 = l1->next;
else
{
l3 = l2->next;
l2->next->next = l1->next;
}
while(l1->next && list2->next) {
if (l1>next->data > l2->data) {
//Step 1. Save the next pointer
Node *tmp = l1->next;
//Step 2. Change next pointer to point L2
l1->next = l2;
//Step 3. Move L2 to temp
l2= tmp;
}
//Step 4. Move L1 ahead
l1 = l1->next;
}
if (!l1->next)
l1->next = l2;
}
In the main function I will pass l3 as the parameter to print(cell * head)
Some tip on how to fix the solution?
This function declaration
void merged_lists (cell * l1, cell * l2, cell * l3);
is invalid because the pointers are passed by values. That is the function deals with copies of original pointers to head nodes of lists. As a result the original pointers will not be changed.
Here is a demonstrative program that shows how the function can be declared and defined.
#include <stdio.h>
#include <stdlib.h>
typedef struct cell
{
int data;
struct cell *next;
} cell;
size_t append( cell **head, const int a[], size_t n )
{
size_t i = 0;
if ( n )
{
while ( *head != NULL ) head = &( *head )->next;
for ( ; ( i < n ) && ( ( *head = malloc( sizeof( cell ) ) ) != NULL ); i++ )
{
( *head )->data = a[i];
( *head )->next = NULL;
head = &( *head )->next;
}
}
return i;
}
void display( const cell *head )
{
for ( ; head != NULL; head = head->next )
{
printf( "%d -> ", head->data );
}
puts( "NULL" );
}
cell * merged_list( cell **list1, cell **list2 )
{
cell *list3 = NULL;
cell **current = &list3;
while ( *list1 != NULL && *list2 != NULL )
{
if ( ( *list2 )->data < ( *list1 )->data )
{
*current = *list2;
*list2 = ( *list2 )->next;
}
else
{
*current = *list1;
*list1 = ( *list1 )->next;
}
current = &( *current )->next;
}
for ( ; *list1 != NULL; current = &( *current )->next )
{
*current = *list1;
*list1 = ( *list1 )->next;
}
for ( ; *list2 != NULL; current = &( *current )->next )
{
*current = *list2;
*list2 = ( *list2 )->next;
}
return list3;
}
int main(void)
{
cell *list1 = NULL;
cell *list2 = NULL;
int a1[] = { 1, 7, 9, 10 };
int a2[] = { 2, 3, 8 };
append( &list1, a1, sizeof( a1 ) / sizeof( *a1 ) );
append( &list2, a2, sizeof( a2 ) / sizeof( *a2 ) );
display( list1 );
display( list2 );
putchar( '\n' );
cell *list3 = merged_list( &list1, &list2 );
display( list1 );
display( list2 );
display( list3 );
return 0;
}
The program output is
1 -> 7 -> 9 -> 10 -> NULL
2 -> 3 -> 8 -> NULL
NULL
NULL
1 -> 2 -> 3 -> 7 -> 8 -> 9 -> 10 -> NULL
The function merged_list can be written shorter
cell * merged_list( cell **list1, cell **list2 )
{
cell *list3 = NULL;
cell **current = &list3;
while ( *list1 != NULL || *list2 != NULL )
{
if ( *list1 == NULL || ( *list2 != NULL && ( *list2 )->data < ( *list1 )->data ) )
{
*current = *list2;
*list2 = ( *list2 )->next;
}
else
{
*current = *list1;
*list1 = ( *list1 )->next;
}
current = &( *current )->next;
}
return list3;
}
I don't think you can resolve this without the tmp variable. Once you override the pointer of the next item in list 1, you basically lose access to all the items in list 1 after the current one. So unless you store that last slice of the list in a temp variable, it's impossible.

Resources