Getting the nth from last of the linked list - c

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;

Related

Question about about splitted Linked list

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

Why isn't my reverse(); function working?

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

Count distinct elements in an list in C [duplicate]

How can i find only the elements that appears once in the list and return the cardinal number?For example if my list consist of {3,2,1,1,2,4} i expect for return the counter to be 4 and not 6 cause we do not count the duplicate numbers.
Here is the code that i have written so far.
struct Node
{
int data;
struct Node *next;
};
int Find_cardinal(struct Node *start)
{
struct Node *ptr1, *ptr2
ptr1 = start;
int counter=0;
/* Pick elements one by one */
while (ptr1 != NULL && ptr1->next != NULL)
{
ptr2 = ptr1;
/* Compare the picked element with rest
of the elements */
while (ptr2->next != NULL)
{
/* If duplicate */
if (ptr1->data == ptr2->next->data)
{
break;
}
else
//do what?
ptr2 = ptr2->next;
}
ptr1 = ptr1->next;
}
return counter;
}
Your function implementation is wrong.
Even the condition in the first while loop
while (ptr1 != NULL && ptr1->next != NULL)
is incorrect because if the list contains only one node the loop will not be executed and the function will return 0.
And within the function the variable counter is not being changed.
Here is a demonstrative program that shows how the function Find_cardinal that is better to name like count_distinct can be implemented.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
typedef struct Node Node_t;
size_t assign( Node_t **head, const int a[], size_t n )
{
while ( *head )
{
Node_t *tmp = *head;
head = &( *head )->next;
free( tmp );
}
size_t i = 0;
for ( ; i < n && ( *head = malloc( sizeof( Node_t ) ) ) != NULL; i++ )
{
( *head )->data = a[i];
( *head )->next = NULL;
head = &( *head )->next;
}
return i;
}
size_t count_distinct( const Node_t *head )
{
size_t n = 0;
for ( const Node_t *current = head; current != NULL; current = current->next )
{
const Node_t *prev = head;
while ( prev != current && prev->data != current->data )
{
prev = prev->next;
}
if ( prev == current ) ++n;
}
return n;
}
FILE * display( const Node_t *head, FILE *fp )
{
for ( ; head != NULL; head = head->next )
{
fprintf( fp, "%d -> ", head->data );
}
fputs( "null", fp );
return fp;
}
int main(void)
{
Node_t *head = NULL;
int a[] = { 1, 2, 1, 1, 3, 4 };
assign( &head, a, sizeof( a ) / sizeof( *a ) );
fputc( '\n', display( head, stdout ) );
printf( "There are %zu distinct data in the list.\n", count_distinct( head ) );
return 0;
}
The program output is
1 -> 2 -> 1 -> 1 -> 3 -> 4 -> null
There are 4 distinct data in the list.
You cannot do it using your current construct. The idea is to iterate through the list and 'remember' or check whether a particular item is duplicate, so somehow you need to store the unique values that have been passed. Below is one naive implementation. Sample output:
Input values
3
2
1
1
2
4
Unique count: 4
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
void printAll(struct Node *start){
struct Node *ptr1;
ptr1 = start;
while (ptr1 != NULL) {
printf("%d\n", ptr1->data);
ptr1 = ptr1->next;
}
}
int countUnique(struct Node *start) {
struct Node *uniqueNodes; //this will hold the unique value
struct Node *ptrInput;
ptrInput = start;
int counter = 0;
/* Pick elements one by one */
while (ptrInput != NULL) {
//Loop through the list which hold the unique value
struct Node *ptrUnique;
ptrUnique = uniqueNodes;
int isFound = 0;
while (ptrUnique != NULL && !isFound) {
if (ptrInput->data == ptrUnique->data) {
isFound = 1; //value is found in the unique list
} //end if
ptrUnique = ptrUnique->next;
} //end while
if (! isFound) { //when not found, then need to add the value in the unique list and increment the counter afterwards
struct Node *newNode = (struct Node *) malloc (sizeof(struct Node));
newNode->data = ptrInput->data;
newNode->next = NULL;
//If uniqueNodes is still empty, then just change the pointer of the uniqueNodes to the newly created item.
//Otherwise, just put the newly created item on the head of the list
if (uniqueNodes == NULL) {
uniqueNodes = newNode;
} else {
newNode->next = uniqueNodes;
uniqueNodes = newNode;
} //end else
counter++;
} //end if
ptrInput = ptrInput->next;
} //end while
return counter;
}
int main(void) {
struct Node *node1 = (struct Node *) malloc (sizeof(struct Node));
struct Node *node2 = (struct Node *) malloc (sizeof(struct Node));
struct Node *node3 = (struct Node *) malloc (sizeof(struct Node));
struct Node *node4 = (struct Node *) malloc (sizeof(struct Node));
struct Node *node5 = (struct Node *) malloc (sizeof(struct Node));
struct Node *node6 = (struct Node *) malloc (sizeof(struct Node));
node1->data = 3;
node2->data = 2;
node3->data = 1;
node4->data = 1;
node5->data = 2;
node6->data = 4;
node1->next = node2;
node2->next = node3;
node3->next = node4;
node4->next = node5;
node5->next = node6;
node6->next = NULL;
printf("Input values\n", NULL);
printAll(node1);
int uniq = countUnique(node1);
printf("\nUnique count: %d\n", uniq);
return 0;
}

how can i swap two nodes without exchanging data

#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head;
void createnodeatbeg(int key) {
struct node *new = (struct node*)malloc(sizeof(struct node));
new->data = key;
new->next = head;
head = new;
}
void printlist() {
struct node *temp = head;
printf("list is:");
while (temp != NULL) {
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
void swapnodes(int x, int y) {
struct node *prevX = NULL;
struct node *prevY = NULL;
struct node *currX = head;
struct node *currY = head;
while (currX->data != x && currX != NULL) {
prevX = currX;
currX = currX->next;
}
printf("not found\n");
while (currY->data != y && currY != NULL) {
prevY = currY;
currY = currY->next;
}
if (currX == NULL || currY == NULL) {
printf("elements not found\n");
return;
}
struct node *swap = currY->next;
prevX->next = currY;
currY->next = prevY;
prevY->next = currX;
currX->next = swap;
}
int main() {
head = NULL;
int nodes, key;
printf("enter number of nodes\n");
scanf("%d", &nodes);
for (int i = 0; i < nodes; i++) {
int data;
printf("enter number\n");
scanf("%d", &data);
createnodeatbeg(data);
}
printlist();
int x, y;
printf("enter the values from the list to be swapped\n");
scanf("%d %d", &x, &y);
swapnodes(x, y);
printf("swapped list is:\n");
printlist();
}
My code works when elements (x and y) are present in the list but if it is not present in the list then error is ./a.out terminated by signal SIGSEGV (Address boundary error).
The problem is that the control doesn't comes out of the first while loop in swapNodes() function.
The code takes a user input and creates a node at the beginning.
The order of operands in the conditions of the while statements is wrong.
while(currX->data!=x && currX!=NULL)
{
prevX=currX;
currX=currX->next;
}
//...
while(currY->data!=y && currY!=NULL)
{
prevY=currY;
currY=currY->next;
}
Here must be
while(currX != NULL && currX->data!=x)
{
prevX=currX;
currX=currX->next;
}
//...
while(currY != NULL && currY->data!=y)
{
prevY=currY;
currY=currY->next;
}
So if for example currX is equal to NULL then the expression currX->data!=x will not be eva;luated.
This code snippet
struct node *swap = currY->next;
prevX->next = currY;
currY->next = prevY;
prevY->next = currX;
currX->next = swap;
is also wrong because for example prevX or prevY can be equal to NULL.
And you have to deal with the head in the function by reference. Otherwise the head node will not be changed.
You should split the function into two functions. The first one founds the node with the given value and the second one will swap found nodes if they are not equal to NULL.
Also it is a bad idea when functions depend on global variables. In fact your program can not deal with two lists simultaneously.
Here is a demonstrative program that shows how the function swap can be implemented.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node ** find( struct node **head, int data )
{
while ( *head && ( *head )->data != data ) head = &( *head )->next;
return head;
}
void swap( struct node **head, int data1, int data2 )
{
struct node **left, **right;
if ( *( left = find( head, data1 ) ) && *( right = find( head, data2 ) ) )
{
struct node *tmp = *left;
*left = *right;
*right = tmp;
tmp = ( *left )->next;
( *left )->next = ( *right )->next;
( *right )->next = tmp;
}
}
int push_front( struct node **head, int data )
{
struct node *tmp = malloc( sizeof( struct node ) );
int success = tmp != NULL;
if ( success )
{
tmp->data = data;
tmp->next = *head;
*head = tmp;
}
return success;
}
void display( struct node **head )
{
for ( struct node *current = *head; current; current = current->next )
{
printf( "%d ", current->data );
}
}
int main(void)
{
const int N = 10;
struct node *head = NULL;
for ( int i = 0; i < N; i++ ) push_front( &head, i );
display( &head );
putchar( '\n' );
for ( int i = 0; i < N; i+=2 )
{
swap( &head, i, i + 1 );
}
display( &head );
putchar( '\n' );
return 0;
}
Its output is
9 8 7 6 5 4 3 2 1 0
8 9 6 7 4 5 2 3 0 1
The problem is in following identical lines:
while(currX->data!=x && currX!=NULL)
while(currY->data!=y && currY!=NULL)
This is because instead of fist checking for NULL and then use it, you are checking for NULL latter. So when x or y is not present then you are trying to access NULL->data, which is giving Segmentation Fault Error (SIGSEGV)
Change it to following respectively:
while(currX!=NULL && currX->data!=x)
while(currY!=NULL && currY->data!=y)

Doubly Linked List Insertion With Recursion in C

I'm more or less just learning C, I was given an simple assignment that deals with doubly linked lists, dynamic data allocation, and recursion. I created an array of just 10 integers and I am trying to put these integers into a sorted doubly linked list using recursion. I am having some trouble with inserting nodes into the linked list; I think I have the first node down, but I'm not sure if the rest makes any sense. Right now I'm also getting a segmentation fault... Thank you for any help!
#include <stdio.h>
#include <stdlib.h>
#define N 10
typedef struct node_ {
int value;
struct node_ *next;
struct node_ *prev;
} node;
void insert(node **head, node *cur, node *p);
void print_list(node *cur);
void print_list(node *cur)
{
if (!cur) {
printf("\n");
return;
} else {
printf("%d ", cur->value);
print_list(cur->next);
}
}
int main(int argc, char *argv[])
{
int i;
int data[N] = {2, 7, 3, 9, 4, 4, 0, 8, 7, 100};
node *p, *head;
head = NULL;
for (i = 0; i < N; i++) {
p = (node *)malloc(sizeof(node));
p->value = data[i];
insert(&head, head, p);
}
print_list(head);
}
void insert(node **head, node *cur, node *p)
{
if(*head == NULL)
{
p->next = (*head);
//(*head)->prev = p;
(*head) = p;
}
if(p->value < cur->value)
{
cur->prev->next = p;
p->prev = cur->prev;
cur->prev = p;
p->next = cur;
}
insert(head, cur, p);
//p->next = *head;
//*head = p;
}
There are a few mistakes in your recursive insert function. It will be clear in the comments of my code:
void insert(node **head, node *cur, node *p)
{
if(*head == NULL) // the list will contain a single element
{
p->next = p->prev = NULL;
*head = p;
return; // we're done for this case!
}
if(p->value < cur->value)
{
p->prev = cur->prev;
p->next = cur;
cur->prev = p;
if(cur->prev != NULL) // what if cur is the head? there is no cur->prev!
cur->prev->next = p;
else
*head = p; // p becomes the new head
return; // we're done!
}
if(cur->next == NULL) // if cur is the last in the list, we just insert p after it
{
cur->next = p;
p->next = NULL;
p->prev = cur;
}
else // now we can proceed recursively and check the next element
insert(head, cur->next, p);
}
I think that it is the function insert itself that has to allocate new node.
It should have two parameters: pointer to head and a value that to be added.
Here is a demonstrative program that shows how the function can be writtem
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct node
{
int value;
struct node *next;
struct node *prev;
} node;
void insert( node **current, int value )
{
if ( *current == NULL || value < ( *current )->value )
{
node *tmp = malloc( sizeof( node ) );
tmp->value = value;
tmp->next = *current;
if ( *current != NULL )
{
tmp->prev = ( *current )->prev;
( *current )->prev = tmp;
}
else
{
tmp->prev = NULL;
}
*current = tmp;
}
else if ( ( *current )->next == NULL )
{
node *tmp = malloc( sizeof( node ) );
tmp->value = value;
tmp->next = ( *current )->next;
tmp->prev = *current;
( *current )->next = tmp;
}
else
{
insert( &( *current )->next, value );
}
}
void print_list( node *current )
{
if ( current == NULL )
{
printf( "\n" ) ;
}
else
{
printf( "%d ", current->value );
print_list( current->next );
}
}
#define N 10
int main( void )
{
node *head = NULL;
srand( ( unsigned int )time( NULL ) );
for ( int i = 0; i < N; i++ )
{
int value = rand() % N;
printf( "%d ", value );
insert( &head, value );
}
printf( "\n" );
print_list( head );
return 0;
}
The program output might look like
4 9 0 0 6 7 2 7 3 3
0 0 2 3 3 4 6 7 7 9
Of course you need to write also a recursive function that will free all allocated mempry for nodes.

Resources