how can i swap two nodes without exchanging data - c

#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)

Related

Linked List Search not working (SIGBUS error and memory leak)

i made a C program implementing linked lists but it won't work... everything i implemented was taken from websites or stackoverflow and it seems to be working for everyone, still does not work for me.
Everytime i run the program (which has an input of a series of word in STDIN, one for row) it gives me Process finished with exit code 138 (interrupted by signal 10: SIGBUS) and debugging it it seems to be stuck at if (strcmp(var->word, searched) == 0) line in the Search function... where am i wrong? I suppose there's something related to pointers but i do not understand what.
The programs starts working and prints something, then breaks and the temp value gets no word as it says read memory from 0x6c62430000600000 failed (0 of 1 bytes read).
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node{
char* word;
struct node* next;
};
int search(struct node** head, char* searched);
void Print(struct node* head);
void Free_All(struct node* head);
void Insert(struct node** head, char* word);
void Delete(struct node* head, char* to_delete);
int Count(struct node* head);
int main() {
static struct node *head = NULL;
int temp;
char word[20];
for (;;) {
temp = scanf("%s", word);
if (strcmp(word, "Print") == 0) {
Print(head);
}
else if (strcmp(word, "Stop") == 0) {
break;
}
else if (temp == EOF) {
Free_All(head);
return 0;
}
else {
Insert(&head, word);
}
}
scanf("%s", word);
int found = search(&head, word);
if (found == 0) {
printf("!! ERROR !!");
return 1;
}
else {
char to_delete[15];
scanf("%s", to_delete);
Delete(head,to_delete);
// DO OTHER STUFF
}
int count = Count(head);
printf("Remaining nodes: %d",count);
Free_All(head);
}
int search(struct node** head, char* searched) {
struct node* var = *head;
while (var != NULL) {
if (strcmp(var->word, searched) == 0)
return 1;
var = var->next;
}
return 0;
}
void Print(struct node* head){
struct node* temp = head;
while (temp) {
printf("%s \n", temp->word);
temp = temp->next;
}
}
void Free_All(struct node* head){
struct node* temp;
temp = head;
while( temp != NULL ){
head= head->next;
free(temp);
temp = head;
}
}
void Insert(struct node** head, char* word)
{
// Create new node
struct node* new_node = (struct node*)malloc(sizeof(struct node));
new_node->word = malloc(strlen(word)+1);
new_node->word = strcpy(new_node->word,word);
new_node->next = NULL;
if (*head== NULL || strcmp((*head)->word, new_node->word) >= 0) {
new_node->next = *head;
*head= new_node;
}
else {
struct node* temp = *head;
temp = *head;
while (temp->next != NULL && strcmp(temp->next->word, new_node->word) < 0) {
temp = temp->next;
}
new_node->next = temp->next;
temp->next = new_node;
}
}
void Delete(struct node* head, char* to_delete) {
struct node *temp = head;
struct node *prev = NULL;
while(temp != NULL){
if(strcmp(temp->word, to_delete) == 0)
{
if(prev == NULL){
head = head->next;
free(temp);
return;
}
else{
prev->next = temp->next;
free(temp);
return;
}
}
prev = temp;
temp = temp->next;
}
}
int Count(struct node* head){
int counter = 0;
struct node* var = head;
while (var != NULL)
{
counter++;
var = var->next;
}
return counter;
}
EDIT: Solved typo in main
The function Delete accepts the pointer to the head node by value
void Delete(struct node* head, char* to_delete);
So the function deals with a copy of the value of the pointer head declared in main
static struct node *head = NULL;
Changing the copy of the value of the pointer head declared in main leaves the value of the original pointer unchanged.
You need to pass the pointer by reference through a pointer to it.
For example the function can be declared and defined the following way.
int Delete( struct node **head, const char *to_delete )
{
while ( *head != NULL && strcmp( ( *head )->word, to_delete ) != 0 )
{
head = &( *head )->next;
}
int success = *head != NULL;
if ( success )
{
struct node *tmp = *head;
*head = ( *head )->next;
free( tmp );
}
return success;
}
Pay attention to that this for loop
for (;;) {
temp = scanf("%s", word);
if (strcmp(word, "Print") == 0) {
Print(head);
}
if (strcmp(word, "Stop") == 0) {
break;
} else if (temp == EOF) {
Free_All(head);
return 0;
} else {
Insert(&head, word);
}
}
has a wrong logic. For example if the user will enter the string "Print" then apart from calling the function Print there will be called the function
Insert(&head, word);
And the function Free_All actually does not free all. It does not free character arrays pointed to by the data member word.
void Free_All(struct node* head){
struct node* temp;
temp = head;
while( temp != NULL ){
head= head->next;
free(temp);
temp = head;
}
}
The function also shall accept the pointer to the head node by reference. It can look the following way
void Free_All( struct node **head )
{
while ( *head != NULL )
{
free( ( *head )->word );
struct node *tmp = *head;
*head = ( *head )->next;
free( tmp );
}
}
I don't have the time or patience to go through line-by-line what's wrong with your code. Right now, Delete of first item on the list does NOT affect the 'head' pointer in 'main()', so using that pointer to Count() or FreeAll() is undefined behaviour.
Here's a bit of code. Use pencil & paper to keep track of the very few variables in use, and where pointers are pointing.
void Print( struct node *p ) {
for( ; p; p = p->next )
printf( "%s ", p->word );
putchar( '\n' );
}
void Insert( struct node **head, char *word ) {
// assemble new node
struct node *nn = (struct node*)malloc( sizeof node );
nn->word = (char*)malloc( strlen( word ) + 1 );
nn->word = strcpy( nn->word, word );
nn->next = NULL;
// find insertion point
struct node *pPrev = NULL;
struct node *pThis = *head;
while( pThis && strcmp( word, pThis->word ) >= 0 )
pPrev = pThis, pThis = pThis->next;
// insert into (possibly empty) list
if( pThis ) nn->next = pThis;
if( pPrev ) pPrev->next = nn;
if( pThis == *head ) *head = nn; // new head?
}
void Delete( struct node **head, char *word ) {
struct node *pPrev = NULL;
for( struct node *pThis = *head; pThis; pPrev = pThis, pThis = pThis->next ) {
int res = strcmp( pThis->word, word );
if( res < 0 ) // not found yet
continue;
if( res > 0 ) // gone beyond, so not present
break;
// Found!
if( pPrev ) pPrev->next = pThis->next; // excise from list
if( pThis == *head ) *head = pThis->next; // change head??
free( pThis->word ); // release memory
free( pThis ); // release memory
break;
}
}
int main() {
struct node *head = NULL;
char word[20];
printf( "Entry phase:\n" );
for( ;; ) {
Print( head );
scanf( "%s", word );
if( strcmp( word, "Stop" ) == 0 )
break;
Insert( &head, word );
}
printf( "Delete phase:\n" );
while( head ) {
Print( head );
scanf( "%s", word );
if( strcmp( word, "Stop" ) == 0 )
break;
Delete( &head, word );
}
return 0;
}
Output:
Entry phase:
baker
baker
delta
baker delta
able
able baker delta
epsilon
able baker delta epsilon
charlie
able baker charlie delta epsilon
Stop
Delete phase:
able baker charlie delta epsilon
able
baker charlie delta epsilon
epsilon
baker charlie delta
charlie
baker delta
baker
delta
delta
{ program halts }

Getting the nth from last of the linked list

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;

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;
}

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