In the code below, I try to change the first node with another node from the list. The problem is that I can't do it, I've been struggling for two days, and I still can't figure it out.
Description code :
enter the number of nodes from the keyboard.
pos1 = 1 - the position of the first node in the list
pos2 - the position of the node to be changed with the first node.
In the function Node *createLinkedList(int n) I create the list of nodes, the function void displayList(Node *head) displays the list, the function void swapFirstNode(Node *head, int pos1, int pos2) should exchange the first node with the node a whose position is read from the keyboard.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *next;
}Node;
Node *createLinkedList(int n);
void displayList(Node *head);
void swapFirstNode(Node *head, int pos1, int pos2);
int main()
{
int n, pos1, pos2;
Node *HEAD = NULL;
printf("\n Enter the number of nodes : ");
scanf("%d", &n);
HEAD = createLinkedList(n);
displayList(HEAD);
printf("\n Enter first node position to swap : ");
scanf("%d", &pos1);
printf("\n Enter second node position to swap : ");
scanf("%d", &pos2);
if(pos1 == 1 && pos2 != 1)
swapFirstNode(HEAD, pos1, pos2);
displayList(HEAD);
}
Node *createLinkedList(int n)
{
int i, value;
Node *head = NULL;
Node *temp = NULL;
Node *curr = NULL;
head = (struct node*)malloc(sizeof(struct node));
if(head == NULL)
{
printf("\n Memory can not be allocated!");
}
else
{
printf("\n Input data for node 1 : ");
scanf("%d", &value);
head->data = value;
head->next = NULL;
temp = head;
for(i=2; i<=n; i++)
{
curr = (struct node *)malloc(sizeof(struct node));
if(curr == NULL)
{
printf(" Memory can not be allocated.");
break;
}
else
{
printf("\n Input data for node %d : ", i);
scanf("%d", &value);
curr->data = value;
curr->next = NULL;
temp->next = curr;
temp = temp->next;
}
}
}
return head;
}
void displayList(Node *head)
{
Node *curr = head;
printf("\n");
printf(" ");
while(curr != NULL)
{
printf("%d->", curr->data);
curr = curr->next;
}
printf("NULL\n");
}
void swapFirstNode(Node *head, int pos1, int pos2)
{
Node *curr = head, *node1 = NULL, *node2 = NULL, *prev_node1 = NULL, *prev_node2 = NULL, *temp = NULL;
int counter = 0, value, i = 1;
/// Find out how many nodes are in list
while(curr != NULL)
{
counter++;
curr = curr->next;
}
if(pos1 < 1 || pos1 > counter || pos2 < 1 || pos2 > counter)
exit(0);
/// Retain the maxim value between two position entered from the keyboard
value = pos1 > pos2 ? pos1 : pos2;
curr = head;
node1 = curr;
while(curr != NULL && i <= value)
{
if(pos2 != 1)
{
/// Set the previous node (the node before the second node), regarding the pos2-1
if(i == (pos2-1))
prev_node2 = curr;
/// Set the seconde node, regarding the pos2 entered from the keyboard
if(i == pos2)
node2 = curr;
}
curr = curr->next;
i++;
}
/// Try to swap the two nodes
if(node1 != NULL && node2 != NULL)
{
if(prev_node2 != NULL)
{
temp = head;
node1->next = node2->next;
node2 = temp;
prev_node2->next = node1;
node2->next = temp->next;
}
}
}
I'm sorry. I get dizzy trying to keep track of all of those counters and pointers and everything.
KISS
The following works quite well swapping the head node with another further down the list. Earlier validation ensures that pos > 1 (the user's idea of "first" node) and pos <= n, the count of the number of nodes in the LL. (ie. The user enters 'swap node 2' and this function is called with n - 1. The function then works with the head being considered node 0.)
Notice that the address of the pointer head is received as a ptr-to-ptr. This allows the function to update the caller's variable. Essential in this case because the function is definitely changing the LL's first node!
Anyway, walk & think your way through these lines. I hope it helps show that fewer moving parts can be more effective.
void swapFirstNode( Node **head, int pos ) {
Node *prev = *head, *cut;
if( pos == 1 ) { // special case of 1st & 2nd swapping
cut = prev->next;
prev->next = prev->next->next;
cut->next = prev;
} else {
while( --pos )
prev = prev->next; // Now pointing at node AHEAD of node to swap out.
cut = prev->next;
Node *cont = cut->next; // Now pointing at continuation (if any)
cut->next = (*head)->next; // Now two heads
prev->next = *head; // head spliced onto 1st section
(*head)->next = cont; // old head joined to continuation
}
*head = cut; // This is the new head!
}
I asked for clarification regarding pos1 but didn't get any so I just disregard that. swapFirstNode will always swap with the first node so pos1 will not be needed.
In order to do the swap, I suggest iterating from head pos2 times, then perform a swap of head->data and the data at the Node you're currently pointing at.
Example:
// pos2 is in the range [0, number of elements)
void swapFirstNode(Node *head, int pos2) {
Node *curr = head;
while(pos2-- > 0 && curr) curr = curr->next;
if(!curr) return; // pos2 was out of bounds
// swap
int tmp = curr->data;
curr->data = head->data;
head->data = tmp;
}
Note: pos2 is zero-based as-is common practice in C. You may present 1-based indices to the user, but I suggest not using 1-based arrays/lists in the rest of the code.
For starters the function createLinkedList has an unpredictable behavior because it creates a node even when the user passes to the function a non-positive value.
Node *createLinkedList(int n)
{
int i, value;
Node *head = NULL;
Node *temp = NULL;
Node *curr = NULL;
head = (struct node*)malloc(sizeof(struct node));
//...
At first it should check the value of the parameter n before starting creating nodes. Also the parameter should have an unsigned integer type as for example size_t because negative values do not make a sense.
The parameter of the function displayList should be declared with qualifier const because the function does not change the displayed list.
void displayList( const Node *head );
In C indices start from 0 not from 1. The index 0 corresponds to the head node.
Calculating the number of nodes in the list
while(curr != NULL)
{
counter++;
curr = curr->next;
}
is inefficient. For example if you want to swap the first two nodes then there is no sense to count all nodes in the list.
And if the user specified invalid positions then the program shall not end abruptly as in your function
if(pos1 < 1 || pos1 > counter || pos2 < 1 || pos2 > counter)
exit(0);
It is enough to report to the user that nodes were not swapped because the user specified invalid positions.
And the pointer to the head node must be passed by reference that is through a pointer to it because the pointer to the head node can be changed within the function.
So the function should be declared like
int swapFirstNode( Node **head, size_t pos1, size_t pos2 );
That is the function returns integer value 1 in case of success or 0 otherwise.
What you need to swap two nodes is to swap the pointers that point to the nodes and their data members next that in turn are pointers.
So write an auxiliary function swap that will swap two pointers.
Here is a demonstration program that shows how it can be done.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *next;
}Node;
Node * createLinkedList( const int a[], size_t n )
{
Node *head = NULL;
Node **current = &head;
while ( n-- && ( *current = malloc( sizeof( Node ) ) ) != NULL )
{
( *current )->data = *a++;
( *current )->next = NULL;
current = &( *current )->next;
}
return head;
}
void displayList( const Node *head )
{
for ( ; head != NULL; head = head->next )
{
printf( "%d -> ", head->data );
}
puts( "null" );
}
void swap( Node **ptr1, Node **ptr2 )
{
Node *tmp = *ptr1;
*ptr1 = *ptr2;
*ptr2 = tmp;
}
int swapFirstNode( Node **head, size_t pos1, size_t pos2 )
{
int success = 0;
if ( pos1 != pos2 )
{
if ( pos2 < pos1 )
{
size_t tmp = pos1;
pos1 = pos2;
pos2 = tmp;
}
Node **first_node = head;
for ( size_t i = 0; *first_node != NULL && i < pos1; i++ )
{
first_node = &( *first_node )->next;
}
success = *first_node != NULL;
if ( success )
{
Node **second_node = first_node;
for ( size_t i = 0; *second_node != NULL && i < pos2 - pos1; i++ )
{
second_node = &( *second_node )->next;
}
success = *second_node != NULL;
if ( success )
{
swap( first_node, second_node );
swap( &( *first_node )->next, &( *second_node )->next );
}
}
}
return success;
}
int main( void )
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
size_t N = sizeof( a ) / sizeof( *a );
Node *head = createLinkedList( a, N );
displayList( head );
swapFirstNode( &head, 0, 1 );
displayList( head );
swapFirstNode( &head, 2, 9 );
displayList( head );
swapFirstNode( &head, 4, 5 );
displayList( head );
}
The program output is
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
1 -> 0 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
1 -> 0 -> 9 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 2 -> null
1 -> 0 -> 9 -> 3 -> 5 -> 4 -> 6 -> 7 -> 8 -> 2 -> null
In fact it is this code snippet
if ( success )
{
swap( first_node, second_node );
swap( &( *first_node )->next, &( *second_node )->next );
}
that swaps two nodes by using the auxiliary function swap that swaps two pointers.
As you can see the function swapFirstNodeis very flexible. It can swap any two nodes of the list. And it indeed swaps two nodes not just data stored in nodes.
Pay attention to that you need to write a function that will clear the list that is that will free all the allocated memory.
Related
What I'm doing is that first I reversed the linked list and then actually I'm trying to get the nth value of a node. The problem is that the function isn't doing anything after it reverses the linked list and doesn't give an error for some reason.
Here's my code:
#include<stdlib.h>
#include<assert.h>
// 1. Create a linked list first
struct Node {
int data;
struct Node* next;
};
// 2. Create traversal function for linked list
void linkedListTraversal(struct Node* ptr) {
while (ptr != NULL) {
printf("%d\n", ptr->data);
ptr = ptr->next;
}
}
// 3. Write a function to get the node value from the tail of the linked list
int getNode(struct Node* head, int positionFromTail) {
int value;
struct Node* prevNode = NULL;
struct Node* currNode = head;
struct Node* nextNode;
while (currNode != NULL) {
nextNode = currNode->next;
currNode->next = prevNode;
prevNode = currNode;
currNode = nextNode;
}
head = prevNode;
struct Node* ptr = head;
int count = 0;
while (ptr != NULL) {
if (count == positionFromTail) {
return (ptr->data);
count = count + 1;
ptr = ptr->next;
}
}
assert(0);
}
int main() {
struct Node* head;
struct Node* second;
struct Node* third;
struct Node* fourth;
head = (struct Node*)malloc(sizeof(struct Node));
second = (struct Node*)malloc(sizeof(struct Node));
third = (struct Node*)malloc(sizeof(struct Node));
fourth = (struct Node*)malloc(sizeof(struct Node));
head->data = 3;
head->next = second;
second->data = 2;
second->next = third;
third->data = 1;
third->next = fourth;
fourth->data = 0;
fourth->next = NULL;
linkedListTraversal(head);
printf("The value of the node is %d", getNode(head, 2));
}
Here's my output and any help will be appreciated.
3
2
1
0
You can have an infinite loop because the pointer ptr is changed only when the condition of the if statement within the loop evaluates to true
while (ptr!=NULL)
{
if (count == positionFromTail)
{
return (ptr->data);
count = count + 1;
ptr = ptr->next;
}
}
Rewrite the for loop at least for example like
while ( ptr != NULL && positionFromTail-- )
{
ptr = ptr->next;
}
if ( ptr != NULL )
{
return ptr->data;
}
else
{
// return some value
return -1;
}
Also the parameter positionFromTail shall have an unsigned integer type. Otherwise you need to check in the beginning of the function whether it has a negative value.
Pay attention to that after exiting the function your list will be broken. The pointer head in main will not be changed after calling the function but the value of the data member next of the node pointed to by the pointer and of other nodes will be changed. So in general your approach is incorrect.
There is no need to reverse the list to find an element at the given position counted from the end of the list.
For starters I would declare the function the following way
int getNode( const struct Node *head, int pos, int *data );
That is the function returns either 1 if there exists a node with the specified position or 0 otherwise. If there is a node with the specified position then the stored value is written in the dereferenced parameter data.
If the value of the parameter pos is not negative then counting of nodes starts from the head otherwise from the end of the list.
Here is a demonstration program.
#include <stdlib.h>
#include <stdio.h>
struct Node
{
int data;
struct Node *next;
};
void clear( struct Node **head )
{
while (*head)
{
struct Node *current = *head;
*head = ( *head )->next;
free( current );
}
}
size_t create( struct Node **head, const int a[], size_t n )
{
clear( head );
size_t i = 0;
while (n-- && ( *head = malloc( sizeof( struct Node ) ) ) != NULL )
{
( *head )->data = *a++;
( *head )->next = NULL;
++i;
head = &( *head )->next;
}
return i;
}
FILE * display( const struct Node *head, FILE *fp )
{
for (; head != NULL; head = head->next)
{
fprintf( fp, "%d -> ", head->data );
}
fputs( "null", fp );
return fp;
}
int getNode( const struct Node *head, int pos, int *data )
{
int success = 0;
if (!( pos < 0 ))
{
while (head != NULL && pos--)
{
head = head->next;
}
if (( success = head != NULL )) *data = head->data;
}
else
{
const struct Node *current = head;
for ( ;current != NULL && pos; ++pos )
{
current = current->next;
}
while (current != NULL )
{
head = head->next;
current = current->next;
}
if (( success = pos == 0 )) *data = head->data;
}
return success;
}
int main( void )
{
struct Node *head = NULL;
const int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
create( &head, a, sizeof( a ) / sizeof( *a ) );
fputc( '\n', display(head, stdout ) );
for (int i = 0, data; getNode( head, i, &data ); i++)
{
printf( "%d: %d; ", i, data );
}
putchar( '\n' );
for (int i = -1, data; getNode( head, i, &data ); i--)
{
printf( "%d: %d; ", i, data );
}
putchar( '\n' );
clear( &head );
}
The program output is
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
0: 0; 1: 1; 2: 2; 3: 3; 4: 4; 5: 5; 6: 6; 7: 7; 8: 8; 9: 9;
-1: 9; -2: 8; -3: 7; -4: 6; -5: 5; -6: 4; -7: 3; -8: 2; -9: 1; -10: 0;
I've got this question where I'm supposed to write a function called - "createList" that gets a linked list(without a dummy element) of ints. The function should remove every element that is bigger than the previous one and the next one.
Also, I have to make a new linked list (without a dummy element) where I place all the removed elements from the original linked list. (The elements should stay in the same order that they appeared in the original linked list).
(createlist is createListEx4() in my code)
For instance, an original linked list : 3->6->1->9->8->4->5;
would be updated to : 3->1->8->4;
The "removed elements" linked list would be: 6->9->5;
The function will return a pointer to the "removed elements" linked list
I wrote this code and I cant seem to understand how to make it work.
There is a memory leak while I print the "removed elements" linked list, and doesn't return the correct elements.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef int data_type;
typedef struct Node2
{
data_type data;
struct Node2 *next;
}Node2;
Node2 * createList2(data_type data);
Node2 * addToFirst2(Node2 *head, data_type data);
Node2 * addToLast2(Node2 *head, data_type data);
void printf_List2(Node2 *head);
void Free_List2(Node2 *head);
Node2* createListEx4(Node2 *);
void Insert_To_Big(Node2 **, int);
void delete_item(Node2 **, Node2 **);
Node2* insert_list();
void main()
{
Node2 *head = NULL;
Node2 *Odd_list = NULL;
head = insert_list(); // A Function which creates a Linked List
printf("You Entered This linked-list:\n");
printf_List2(head); // A Function which prints the Imported List
Odd_list = createListEx4(head); // a Function which Returns The address to The Odd linked list
printf("The Odd Linked-List is:\n");
printf_List2(Odd_list); // A Function Which Prints the Odd List
Free_List2(Odd_list); // Free The list After we have finished using it
}
Node2* insert_list() // A function Which imports numbers to the linked list till -1
{
int Num;
Node2 *Head = NULL;
printf("Please enter the Number you want to Sort untill -1:\n");
scanf("%d", &Num);
while (Num != -1)
{
Head = addToLast2(Head, Num); // The last entered Number will be the Head
scanf("%d", &Num);
}
return Head;
}
Node2* createListEx4(Node2 *head) // **head will be in the end the Even Linked List**
{
Node2 *Big = NULL;
Node2 *temp, *step, *prev = NULL;
if (head == NULL) // if the linked list is empty
return NULL;
if (head->data > head->next->data)
{
Insert_To_Big(&Big, head->data);
temp = head;
head = head->next;
free(temp);
}
prev = head;
// At this point we start runnig the list from an even Number //
step = head;
while (step ->next ->next != NULL)
{
if ((step->data < step->next->data) && (step->next->data > step->next->next->data))
{
Insert_To_Big(&Big, step->next->data);
delete_item(&step, &prev);
}
else
{
prev = step;
step = step->next;
}
}
if (step->data < step->next->data)
{
Insert_To_Big(&Big, step->next->data);
free(step->next);
}
step = NULL;
printf("The Even Linked-List is:\n");
printf_List2(head);
Free_List2(head);
return Big;
}
void delete_item(Node2 **step, Node2 **prev) //A Funtions Which Deletes a Node and Connects the prev Node to the Next one
{
Node2 *temp = *step;
*step = (*step)->next;
(*prev)->next = *step;
free(temp);
}
void Insert_To_Big(Node2 **head, int Num) // A Function Which Creates The Odd linked list
{
*head = addToLast2(*head, Num);
}
Node2 * createList2(data_type data)
{
Node2 *temp = (Node2*)malloc(sizeof(Node2));
temp->data = data;
temp->next = NULL;
return temp;
}
Node2 * addToFirst2(Node2 *head, data_type data)
{
Node2 *temp = createList2(data);
temp->next = head;
return temp;
}
Node2 * addToLast2(Node2 *head, data_type data)
{
Node2 *p = head;
Node2 *temp = createList2(data);
if (head == NULL)
return temp;
while (p->next != NULL)
p = p->next;
p->next = temp;
return head;
}
void printf_List2(Node2 *head)
{
Node2 *p = head;
while (p != NULL)
{
printf("%d, ", p->data);
p = p->next;
}
printf("\n\n");
}
void Free_List2(Node2 *head)
{
Node2 *temp = head;
while (temp != NULL)
{
head = head->next;
free(temp);
temp = head;
}
}
My five cents.:)
Here is a demonstrative program. I named the corresponding function split. The function is called for different corner cases.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int data;
struct Node *next;
} Node;
void clear( Node **head )
{
while ( *head )
{
Node *tmp = *head;
*head = ( *head )->next;
free( tmp );
}
}
size_t assign( Node **head, const int a[], size_t n )
{
clear( head );
size_t count;
for ( size_t i = 0; i < n && ( *head = malloc( sizeof( Node ) ) ) != NULL; i++ )
{
( *head )->data = a[i];
( *head )->next = NULL;
head = &( *head )->next;
++count;
}
return count;
}
FILE * display( const Node *head, FILE *fp )
{
for ( ; head != NULL; head = head->next )
{
fprintf( fp, "%d -> ", head->data );
}
fputs( "null", fp );
return fp;
}
Node * split( Node **head )
{
Node *out_head = NULL;
Node **out_current = &out_head;
for ( Node *prev = NULL; *head != NULL; )
{
if ( prev != NULL || ( *head )->next != NULL )
{
if ( ( prev == NULL || prev->data < ( *head )->data ) &&
( ( *head )->next == NULL || ( *head )->next->data < ( *head )->data ) )
{
Node *tmp = *head;
*head = ( *head )->next;
tmp->next = NULL;
*out_current = tmp;
out_current = &tmp->next;
}
else
{
prev = *head;
}
}
else
{
prev = *head;
}
if ( *head != NULL ) head = &( *head )->next;
}
return out_head;
}
int main(void)
{
Node *head = NULL;
int a1[] = { 3 };
assign( &head, a1, sizeof( a1 ) / sizeof( *a1 ) );
fputc( '\n', display( head, stdout ) );
Node *head2 = split( &head );
fputc( '\n', display( head, stdout ) );
fputc( '\n', display( head2, stdout ) );
clear( &head2 );
clear( &head );
putchar( '\n' );
int a2[] = { 3, 6 };
assign( &head, a2, sizeof( a2 ) / sizeof( *a2 ) );
fputc( '\n', display( head, stdout ) );
head2 = split( &head );
fputc( '\n', display( head, stdout ) );
fputc( '\n', display( head2, stdout ) );
clear( &head2 );
clear( &head );
putchar( '\n' );
int a3[] = { 6, 3 };
assign( &head, a3, sizeof( a3 ) / sizeof( *a3 ) );
fputc( '\n', display( head, stdout ) );
head2 = split( &head );
fputc( '\n', display( head, stdout ) );
fputc( '\n', display( head2, stdout ) );
clear( &head2 );
clear( &head );
putchar( '\n' );
int a4[] = { 3, 6, 1, 9, 8, 4, 5 };
assign( &head, a4, sizeof( a4 ) / sizeof( *a4 ) );
fputc( '\n', display( head, stdout ) );
head2 = split( &head );
fputc( '\n', display( head, stdout ) );
fputc( '\n', display( head2, stdout ) );
clear( &head2 );
clear( &head );
return 0;
}
The program output is
3 -> null
3 -> null
null
3 -> 6 -> null
3 -> null
6 -> null
6 -> 3 -> null
3 -> null
6 -> null
3 -> 6 -> 1 -> 9 -> 8 -> 4 -> 5 -> null
3 -> 1 -> 8 -> 4 -> null
6 -> 9 -> 5 -> null
Your code is much more complicated than need and also contains a number of logical errors.
For instance, you shouldn't use malloc and free when moving node from one list to the other. Just change pointers.
And this part from the start of createListEx4
if (head->data > head->next->data)
{
Insert_To_Big(&Big, head->data);
temp = head;
head = head->next;
free(temp);
}
You only compare head to head->next but that's not what your requirements are saying. Further, you simply free the element but it should have been moved - not freed.
Below is an implementation you can look at. There are room for improvements but I tried to keep the code simple so that it's easy to understand.
typedef int data_type;
typedef struct node
{
data_type data;
struct node *next;
} node;
node* create_static_list(void)
{
// Bypassing check for NULL for readability - don't do it in real code
node* r = NULL;
int a[] = {5, 4, 8, 9, 1, 6, 3};
for (size_t i = 0; i < sizeof a / sizeof a[0]; ++i)
{
node* t = malloc(sizeof *t);
t->next = r;
t->data = a[i];
r = t;
}
return r;
}
void add_to_other_list(node** head, node* p)
{
static node* tail = NULL;
p->next = NULL;
if (tail == NULL)
{
*head = p;
}
else
{
tail->next = p;
}
tail = p;
}
node* remove_special(node* p)
{
node* res = NULL;
if (p == NULL) return res; // 0 elements
if (p->next == NULL) return res; // 1 element
if (p->next->next == NULL) // 2 elements
{
// Special handling of last element in list
if (p->next->data > p->data)
{
// Move p->next to other list
add_to_other_list(&res, p->next);
p->next = NULL;
return res;
}
}
// Repeat as long as the list has minimum 3 elements
while (p->next->next)
{
if ((p->next->data > p->data) &&
(p->next->data > p->next->next->data))
{
// Move p-next
node* t = p->next;
p->next = p->next->next;
add_to_other_list(&res, t);
}
p = p->next;
}
if (p->next == NULL) return res; // 1 element left, just return
if (p->next->next == NULL) // 2 elements left - check last element
{
// Special handling of last element in list
if (p->next->data > p->data)
{
// Move p->next to other list
add_to_other_list(&res, p->next);
p->next = NULL;
}
}
return res;
}
// This is OPs function (expect for variable names)
void print_list(node *p)
{
while (p != NULL)
{
printf("%d, ", p->data);
p = p->next;
}
printf("\n\n");
}
int main(void)
{
node* head = create_static_list();
print_list(head);
node* removed = remove_special(head);
print_list(head);
print_list(removed);
}
OUTPUT
3, 6, 1, 9, 8, 4, 5,
3, 1, 8, 4,
6, 9, 5,
There is no need to create new elements for the returned list. Elements removed from the original list can be moved to the returned list by manipulating the links.
An element is to be moved from the original list to the returned list if its data is bigger than all of its neighboring elements that exist. There are two special cases to consider: (1) if the original list is empty, the returned list is empty; (2) if the original list consists of a single element, move it to the returned list. (Case (2) was not explicitly stated by OP, but it seems consistent. It only affects the tests for whether an element should be moved or not, which can be changed easily.)
Since the first element can be removed from the original list the function's parameter should be a double pointer, pointing to the link to the first element of the list.
The following function implements the list processing described above:
Node2 *createListEx4(Node2 **list)
{
Node2 *bigHead = NULL; /* Head of 'big' list. */
Node2 **bigEnd = &bigHead; /* Pointer to terminating link of 'big' list. */
Node2 *prev = NULL; /* Previous element to compare data with. */
Node2 *next; /* Next element to compare data with. */
Node2 *cur; /* Current element. */
while ((cur = *list) != NULL)
{
next = cur->next;
if ((!prev || cur->data > prev->data) &&
(!next || cur->data > next->data))
{
/* Move current element to 'big' list. */
*bigEnd = cur;
bigEnd = &cur->next;
*list = next;
}
else
{
/* Skip over current element. */
list = &cur->next;
}
prev = cur;
}
/* Terminate the 'big' list. */
*bigEnd = NULL;
return bigHead;
}
Examples:
Original: (null)
Returned: (null)
Remaining: (null)
Original: 1
Returned: 1
Remaining: (null)
Original: 1 2
Returned: 2
Remaining: 1
Original: 2 1
Returned: 2
Remaining: 1
Original: 1 2 3
Returned: 3
Remaining: 1 2
Original: 1 3 2
Returned: 3
Remaining: 1 2
Original: 2 1 3
Returned: 2 3
Remaining: 1
Original: 2 3 1
Returned: 3
Remaining: 2 1
Original: 3 1 2
Returned: 3 2
Remaining: 1
Original: 3 2 1
Returned: 3
Remaining: 2 1
I'm writing a program in C for reversing a circular singly linked list. I keep getting segmentation fault for some reason. I'm sure the problem is with the reverse function as I tried commenting the function call, the program works fine.
For my reverse() function, I have used 3 pointers: prev, next and curr. The logic is that I'll run a loop till curr takes the address of head, which will be stored in the link part of the last node since it is a circular linked list. I'll keep updating curr->link using prev pointer which will change its link from the next to its previous node.
When the loop breaks, head->link = prev; and head = prev; will update the respective addresses such that they point to the first node of the reversed list.
//reversing CLL
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *link;
} *head;
void reverse() {
struct node *prev = NULL, *curr = head, *next;
while (curr != head) {
next = curr->link;
curr->link = prev;
prev = curr;
curr = next;
}
head->link = prev;
head = prev;
}
void createList(int n) {
int i, data;
head = (struct node *)malloc(sizeof(struct node));
struct node *ptr = head, *temp;
printf("Enter data of node 1\t");
scanf("%d", &data);
head->data = data;
head->link = NULL;
for (i = 2; i <= n; i++) {
temp = (struct node *)malloc(sizeof(struct node));
printf("Enter data of node %d\t", i);
scanf("%d", &data);
temp->data = data;
temp->link = NULL;
ptr->link = temp;
ptr = ptr->link;
}
ptr->link = head;
}
void disp() {
struct node *ptr = head;
do {
printf("%d\t", ptr->data); //gdb debugger shows problem is in this line
ptr = ptr->link;
} while (ptr != head);
}
int main() {
int n;
printf("Enter no of nodes to be created\t");
scanf("%d", &n);
createList(n);
printf("\n\nList is displayed below!\n");
disp();
printf("\n\nReversing list ...\n");
reverse(); // on commenting this call, disp() function
// works accurately showing node data non-reversed
disp();
printf("\n\nList successfully reversed!\n");
}
The loop in the reverse() function exits immediately because curr is initialized to the value of head so the test while (curr != head) is false at the first iteration.
reverse() then sets head->link to NULL and finally head is also set to NULL (the initial value of prev), which explains the segmentation fault in the subsequent disp() function where you use a do { } while (pre != head) that cannot handle an empty list.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *link;
};
struct node *reverse(struct node *head) {
struct node *prev = NULL, *curr = head;
if (head) {
do {
struct node *next = curr->link;
curr->link = prev;
prev = curr;
curr = next;
} while (curr != head);
curr->link = prev;
head = prev;
}
return head;
}
struct node *createList(int n) {
struct node *head = NULL, *tail = NULL, *temp;
int i;
for (i = 1; i <= n; i++) {
temp = (struct node *)malloc(sizeof(struct node));
temp->data = 0;
temp->link = NULL;
printf("Enter data of node %d\t", i);
scanf("%d", &temp->data);
if (head == NULL) {
head = temp;
} else {
tail->link = temp;
}
tail = temp;
temp->link = head;
}
return head;
}
void disp(struct node *head) {
if (head) {
struct node *ptr = head;
do {
printf("%d\t", ptr->data);
ptr = ptr->link;
} while (ptr != head);
}
}
int main() {
struct node *head;
int n = 0;
printf("Enter no of nodes to be created\t");
scanf("%d", &n);
head = createList(n);
printf("\n\nList is displayed below!\n");
disp(head);
printf("\n\nReversing list ...\n");
head = reverse(head);
disp(head);
printf("\n\nList successfully reversed!\n");
// should free the list
return 0;
}
For starters it is a bad idea to use the global variable head
struct node {
int data;
struct node *link;
} *head;
In this case the functions depend on the global variable and you can not use more than one list in a program.
Due to this initialization
struct node *prev = NULL, *curr = head, *next;
^^^^^^^^^^^^
the condition of the while loop
while (curr != head) {
is never evaluates to true because initially the pointer curr is equal to the pointer head.
Moreover if the list is empty then this statement
head->link = prev;
invokes undefined behavior.
Here is a demonstrative program that shows how the list can be declared in main and then reversed.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *link;
};
size_t assign( struct node **head, const int a[], size_t n )
{
while ( *head )
{
struct node *tmp = *head;
*head = ( *head )->link;
free( tmp );
}
size_t total = 0;
struct node *first = NULL;
while ( total < n && ( *head = malloc( sizeof( struct node ) ) ) != NULL )
{
( *head )->data = a[total];
( *head )->link = NULL;
++total;
if ( first == NULL ) first = *head;
head = &( *head )->link;
}
if ( first != NULL ) *head = first;
return total;
}
void display( const struct node *head )
{
if ( head != NULL )
{
const struct node *current = head;
do
{
printf( "%d -> ", current->data );
} while ( ( current = current->link ) != head );
}
puts( "null" );
}
struct node * reverse( struct node **head )
{
if ( *head )
{
struct node *last = *head;
struct node *prev = NULL;
while ( ( *head )->link != last )
{
struct node *current = *head;
*head = ( *head )->link;
current->link = prev;
prev = current;
}
( *head )->link = prev;
last->link = *head;
}
return *head;
}
int main(void)
{
struct node *head = NULL;
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
assign( &head, a, sizeof( a ) / sizeof( *a ) );
display( head );
display( reverse( &head ) );
display( reverse( &head ) );
return 0;
}
The program output is
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0 -> null
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I'm writing a program that creates a doubly linked list and removes a element with negative value from it. Everything pretty much works, except for the part when I called the modify function and when I try to delete it, program crashes. Any suggestions?
/*
*Given a doubly linked lists with +ve and -ve key values.
*Write a function to delete all the nodes with negative key values.
*/
#include<stdio.h>
#include<stdlib.h>
struct list {
int data;
struct list *next;
struct list *prev;
};
struct list *head = NULL;
struct list* create(int);
void modify(struct list*);
int main(void) {
int n, i, value;
struct list *temp;
printf("Enter the count of node :");
scanf("%d",&n);
for (i = 0; i < n; i ++) {
printf("Enter the value of node: ");
scanf("%d",&value);
create(value);
}
temp = head;
printf("\nDoubly linked list is created and the list is as follows : \n");
while (temp != NULL) {
printf("%d ",temp -> data);
temp = temp -> next;
}
modify(head);
}
struct list* create(int value) {
struct list *new_node, *temp;
temp = head;
new_node = (struct list*)malloc(sizeof(struct list));
new_node -> data = value;
new_node -> next = NULL;
new_node -> prev = NULL;
if (head == NULL) {
head = new_node;
}
else {
while (temp -> next != NULL) {
temp = temp -> next;
}
temp -> next = new_node;
new_node -> prev = temp;
}
return head;
}
void modify(struct list *head) {
struct list *current_node, *prev_node, *next_node, *temp;
temp = head;
while (temp -> next != NULL) {
if (temp -> data < 0) {
current_node = temp;
prev_node = temp -> prev;
next_node = temp -> next;
prev_node -> next = next_node;
next_node -> prev = prev_node;
free(current_node);
}
}
printf("\nThe modified doubly linked list is : \n ");
temp = head;
while (temp -> next != NULL) {
printf("%d",temp -> data);
temp = temp -> next;
}
}
See the examples of Vlad from Moscow to have a better understanding of what you were doing.
I shall go trough your code and tell you what I would change.
/*
*Given a doubly linked lists with +ve and -ve key values.
*Write a function to delete all the nodes with negative key values.
*/
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
First of all: you're making a (doubly linked) list of nodes, not a list of lists. Call it a Node. Also, you can do a typedef to prevent you from writing struct Node all the time.
struct Node {
int data;
struct Node* next;
struct Node* prev;
};
void append(struct Node** head, int value); // variable names aren't needed here
struct Node* findLastNode(struct Node** head);
void removeNegativeNodes(struct Node** head);
void removeNode(struct Node** head, struct Node* currNode);
int main(void)
{
Try not to use global variables. There are many reasons to be found why not to use them, but in here it's possible to don't use them as well. Imagine having thousands of lines of code, you won't be able to have a decent view on the code.
struct Node* head = NULL;
struct Node* p; // temp-<p>ointer
int n, value;
printf("Enter the count of node :");
scanf("%d", &n);
You only need i in the for-loop, so keep it there.
for (int i = 0; i < n; ++i) {
printf("Enter the value of node: ");
scanf("%d", &value);
Make sure your function names are clear and tell you what they do. create() would tell me it creates a Node, but not that it also appends the node.
append(&head, value);
}
// this can be in a function! (A) printData
p = head; // temp-<p>ointer
printf("\nDoubly linked list is created and the list is as follows : \n");
while (p != NULL) {
printf("%d <=> ", p->data);
p = p->next;
}
printf("NULL\n");
Look at what you're doing: perhaps you want to make a general function to split the code? Here you're again going trough the list and printing out it's data members.
// this can be in a function! (B) printData
removeNegativeNodes(&head);
printf("\nThe modified doubly linked list is : \n");
p = head;
while (p != NULL) {
printf("%d <=> ", p->data);
p = p->next;
}
printf("NULL\n");
}
struct Node* findLastNode(struct Node** head)
{
struct Node* p = *head;
if (p != NULL)
while (p->next != NULL)
p = p->next;
return p;
}
Since your head has to be changed, you'll have to pass the address of the head as well. Also, split your code a bit, so it's easier for yourself to have an idea of your code's structure. If your function is 40 rules long, it will take longer to find out where the cause of the bug is located (exactly).
void append(struct Node** head, int value)
{
struct Node* lastNode = findLastNode(head);
struct Node* nextNode = (struct Node*)malloc(sizeof(struct Node));
if (lastNode != NULL) {
lastNode->next = nextNode;
nextNode->prev = lastNode;
}
else {
*head = nextNode;
nextNode->prev = NULL;
}
nextNode->next = NULL;
nextNode->data = value;
}
Here as well: the first number can be negative, so make sure you can access the head variable by it's address. Also, again keep it simple and split your code in functions removeNegativeNodes > removeNode.
void removeNegativeNodes(struct Node** head)
{
struct Node* p = *head;
struct Node* temp;
while (p != NULL) {
temp = p->next;
if (p->data < 0)
removeNode(head, p);
p = temp;
}
}
void removeNode(struct Node** head, struct Node* currNode)
{
if (currNode->next != NULL)
currNode->next->prev = currNode->prev;
if (currNode->prev != NULL)
currNode->prev->next = currNode->next;
else
*head = currNode->next;
free(currNode);
}
I've tested the code and it should work. Having it worked properly is not important though, it's understanding what happens. I recommend you having a closer look to it. Goodluck!
Your definition of a doubly-linked list does not make great sense.
The list should contain two pointers: to the head node and to the tail node of the list.
So you need to define two structures. The first one defines the node and the second one defines the list itself.
In this case you need not to traverse the whole list to append a new node to the tail of the list.
The function create with the confusing name is based on the global variable head while the function modify instead gets the variable through a parameter.
This is very confusing. As result for example you can not create two lists in a program.
So as the function modify gets the pointer to the head node by value then it means that it deals with a copy of the pointer to the head node. As a result any changes of the pointer to the head node in the function does not influence on the original pointer to the head node.
This loop in the function modify
temp = head;
while (temp -> next != NULL) {
in general can invoke undefined behavior because it is not excluded that the pointer to the head node can be equal to NULL.
And in any case the condition of the loop does not make sense because within the loop you are considering not the next node but the current
while (temp -> next != NULL) {
if (temp -> data < 0) {
So a question arises if temp->next is equal to NULL but the value of the current node pointed to by the pointer temp is negative does it mean that this node will not be removed?
Pay attention to that if you will write the condition of the loop correctly nevertheless either data member prev of the removed node or the data member next of the removed node or even the both can be equal to NULL. In this case these statements
prev_node = temp -> prev;
next_node = temp -> next;
prev_node -> next = next_node;
^^^^^^^^^^^^^^^^^
next_node -> prev = prev_node;
^^^^^^^^^^^^^^^^^
again can invoke undefined behavior.
here is a demonstrative program that shows how the list and its functions can be defined. Investigate it.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct Node
{
int data;
struct Node *next;
struct Node *prev;
};
struct List
{
struct Node *head;
struct Node *tail;
};
int push_back( struct List *list, int data )
{
struct Node *new_node = malloc( sizeof( struct Node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->next = NULL;
if ( list->head == NULL )
{
new_node->prev = NULL;
list->head = list->tail = new_node;
}
else
{
new_node->prev = list->tail;
list->tail = list->tail->next = new_node;
}
}
return success;
}
void remove_if( struct List *list, int predicate( int ) )
{
struct Node *prev = NULL;
for ( struct Node **current = &list->head; *current != NULL; )
{
if ( predicate( ( *current )->data ) )
{
struct Node *tmp = *current;
if ( ( *current )->next != NULL )
{
( *current )->next->prev = ( *current )->prev;
}
*current = ( *current )->next;
free( tmp );
}
else
{
prev = *current;
current = &( *current )->next;
}
}
list->tail = prev;
}
void display( const struct List *list )
{
for ( const struct Node *current = list->head; current != NULL; current = current->next )
{
printf( "%d -> ", current->data );
}
puts( "null" );
}
void display_reverse( const struct List *list )
{
for ( const struct Node *current = list->tail; current != NULL; current = current->prev )
{
printf( "%d -> ", current->data );
}
puts( "null" );
}
int is_negative( int data )
{
return data < 0;
}
int main(void)
{
struct List list = { .head = NULL, .tail = NULL };
const size_t N = 10;
srand( ( unsigned int )time( NULL ) );
for ( size_t i = 0; i < N; i++ )
{
push_back( &list, rand() % N - N / 2 );
}
display( &list );
display_reverse( &list );
putchar( '\n' );
remove_if( &list, is_negative );
display( &list );
display_reverse( &list );
putchar( '\n' );
return 0;
}
The program output might look like
2 -> 4 -> 3 -> -5 -> 3 -> -3 -> -3 -> -2 -> 0 -> 2 -> null
2 -> 0 -> -2 -> -3 -> -3 -> 3 -> -5 -> 3 -> 4 -> 2 -> null
2 -> 4 -> 3 -> 3 -> 0 -> 2 -> null
2 -> 0 -> 3 -> 3 -> 4 -> 2 -> null
The create() function returns a linked list item. so you have to assign the return value to an item. Also the definition of pointers inside the struct is completely wrong.
struct list {
int data;
struct list *next;
struct list *prev;
};
struct list *head = NULL;
struct list* create(int); //function prototype
void modify(struct list*);//function prototype
int main(void) {
int n, i, value;
struct list *temp;
printf("Enter the number of nodes :");
scanf("%d",&n);
for (i = 0; i < n; i ++) {
printf("Enter the value of node: ");
scanf("%d",&value);
create(value);
}
temp = head;
printf("\nDoubly linked list is created and the list is as follows : \n");
while (temp != NULL) {
printf("%d ",temp -> data);
temp = temp -> next;
}
modify(head);
}
void create(int value) {
struct list* point = head;
while(point->next){
if(point->data != value)
point = point->next;
else{
printf("Data exists\n");
return NULL;
}
}
struct list* item = (struct list*)malloc(sizeof(struct list));
item->data = value;
item->next = NULL;
item->prev = point;
}
void modify(struct list *head) {
struct list *current_node, *prev_node, *next_node, *temp;
temp = head;
while (temp -> next != NULL) {
if (temp -> data < 0) {
temp->prev->next = temp->next;
temp->next->prev = temp->prev;
free(temp);
}
temp = temp->next;
}
printf("\nThe modified doubly linked list is : \n ");
temp = head;
while (temp -> next != NULL) {
printf("%d",temp -> data);
temp = temp -> next;
}
}
I hope this will work for you.
I have this piece of code, it deletes the last element from a linked list. What changes do I have to make so it will delete the last TWO elements of the linked list?
void deletesEnd() {
struct node *temp, *last;
temp = head;
last = temp;
while (temp != NULL && temp->next != NULL) {
last = temp;
temp = temp->next;
}
if (last == temp) {
free(temp);
head = NULL;
} else {
free(last->next);
last->next = NULL;
}
}
The simplest solution to remove the last 2 elements of the list is to call deletesEnd() twice. Note that deletesEnd() should take head as an argument and return the new value. You would delete the last 2 by issuing a nested call:
struct node *deletesEnd(struct node *head) {
struct node *temp, *last;
last = temp = head;
while (temp && temp->next != NULL) {
last = temp;
temp = temp->next;
}
if (last == head) {
free(head);
head = NULL;
} else {
free(last->next);
last->next = NULL;
}
return head;
}
Delete the last element: head = deletesEnd(head);
Delete the last 2 elements: head = deletesEnd(deletesEnd(head));
The simplicity of the design more than compensates for the overhead of enumerating the list twice.
If you absolutely want a specific function, you can extend your approach this way:
struct node *deleteLast2Nodes(struct node *head) {
struct node *temp, *last;
last = temp = head;
while (temp && temp->next != NULL && temp->next->next != NULL) {
last = temp;
temp = temp->next;
}
if (last == head) {
if (head) {
free(head->next);
}
free(head);
head = NULL;
} else {
free(last->next->next);
free(last->next);
last->next = NULL;
}
return head;
}
Here is a demonstrative program that shows how two last nodes can be deleted simultaneously. In fact the function is similar to your function except it checks not only the next node but also the next->next node.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int value;
struct node *next;
} *head;
void push( int value )
{
struct node *tmp = malloc( sizeof( struct node ) );
tmp->value = value;
tmp->next = head;
head = tmp;
}
void display()
{
for ( struct node *current = head; current; current = current->next )
{
printf( "%d ", current->value );
}
}
void deleteLastTwo()
{
struct node *current = head;
struct node *prev = head;
if ( current && current->next )
{
while ( current->next->next )
{
prev = current;
current = current->next;
}
}
if ( current )
{
if ( current->next )
{
free( current->next );
}
if ( prev == current )
{
head = NULL;
}
else
{
prev->next = NULL;
}
free( current );
}
}
int main(void)
{
const int N = 11;
for ( int i = N; i != 0; i-- ) push( i - 1 );
display();
printf( "\n" );
while ( head )
{
deleteLastTwo();
display();
printf( "\n" );
}
return 0;
}
The program output is
0 1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6
0 1 2 3 4
0 1 2
0
Take into account that it is not a good idea when the head node is declared like a global variable. It is better when it can be declared like a local variable. In this case you will need to rewrite the methods of the list because in most cases the current methods will not work correctly.
This logic will delete your last 2 node in singly linked list.
void deletesEnd()
{
struct node *temp, *last;
temp = head;
last = temp;
while (temp->next->next != NULL)
{
last = temp->next;
if(last->next->next!=NULL)
temp = temp->next;
else
break;
}
struct node *ptr=last->next;
last->next=ptr->next;
free(ptr);
temp->next=last->next;
free(last);
}
For fun & education: simple recursive version.
The function return := the number of nodes below us
After the recursion returns, we can decide if we are too close to the tail.
and remove ourselves
because we pass a pointer to pointer, this should also work for lists of size=2 and smaller
unsigned del_tail_n(struct llist **pp, unsigned nn)
{
unsigned pos;
if (!*pp) return 0;
// this recursive call returns 0 iff (*pp)->next is NULL
pos = del_tail_n( &(*pp)->next, nn);
if (pos < nn) {
// free (*pp);
*pp = NULL;
}
return 1+pos;
}
For those who don't like recursion, here is a non-recursive version.
[do note that both versions work for empty lists (*pp == NULL) , or for lists smaller than nn ]
void del_tail_n2(struct llist **pp, unsigned nn)
{
struct llist *p;
/* Advance p pointer n positions down, starting from *pp. */
for (p= *pp; p; p=p->next) {
if (nn-- < 1) break;
}
/* Do a synchronous walk down for both p and *pp, until p is NULL. */
for ( ; p; p=p->next) {
pp = &(*pp)->next;
}
/* Now, *pp is the first node to delete
** Delete it and everything below it.
*/
for ( ;(p = *pp); ){
*pp = p->next;
// free (p);
}
return;
}