union of linked lists - c

I have created a program to find union of 2 linked list. My logic is first of all take a new list insert list1 contents into this list and insert only those values from list2 which are not in result list. My code is:
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
/* Linked list node */
struct node
{
int data;
struct node* next;
};
struct node* result;
struct node *newNode(int data)
{
struct node *new_node = (struct node *) malloc(sizeof(struct node));
new_node->data = data;
new_node->next = NULL;
return new_node;
}
/* Function to insert a node at the beginning of the Doubly Linked List */
void push(struct node** head_ref, int new_data)
{
/* allocate node */
struct node* new_node = newNode(new_data);
new_node->next=*head_ref;
*head_ref=new_node;
}
struct node *union3(struct node *first, struct node *second, struct node *result)
{
int flag = 0;
struct node *temp = NULL;
temp = first;
struct node *temp2 = NULL;
temp2 = second;
int value;
while (temp != NULL)
{
push(&result, temp->data); // pushing first list values in result
temp = temp->next;
}
while (second)
{
present(second->data, result); // comparing second list each member with result
second = second->next;
}
return result;
}
void present(int data, struct node *result1)
{
printf("The value in the beginning of present function is:");
int flag = 0;
while (result1)
{
if (result1->data == data)
{
flag++;
}
result1 = result1->next;
}
if (flag > 0)
{
printf("");
}
else
{
push(&result, data);
}
}
void printList(struct node *node)
{
while(node != NULL)
{
printf("%d ", node->data);
node = node->next;
}
printf("\n");
}
/* Drier program to test above function */
int main(void)
{
struct node* first = NULL;
struct node* second=NULL;
// struct node* result=NULL;
struct node* union2=NULL;
// create first list 7->5->9->4->6
push(&first, 6);
push(&first, 4);
push(&first, 9);
push(&first, 5);
push(&first, 7);
printf("First list is:");
printList(first);
push(&second,6);
push(&second,4);
push(&second,9);
push(&second,11);
push(&second,12);
printf("second list is");
printList(second);
printf("their union is:");
union2=union3(first,second,result);
printf("Union of 2 lists is:");
printList(union2);
return 0;
}
Basically my logic is right but a problem is coming in result variable. Its list1 values pushed in it gets lost in it when it goes in present() function even though I have made result a global variable. Can anybody tell why output is displaying only list1 contents as:
output:6 4 9 5 7

With your algorithm if list1 has duplicates they will show in the final result, but if list2 has duplicates they will not show in the final result which is something you probably don't want.
Also I think you meant to use temp2 instead of second in:
while(second)
{
present(second->data,result); //comparing second list each member with result
second=second->next;
}
and finally this took me some time but I found your error:
push(&result,data);
should be result1
Hope this helps!

Catch! :) All you else need is to add a function that will free allocated memory for the lists.
#include <stdlib.h>
#include <stdio.h>
/* Linked list node */
struct node
{
int data;
struct node *next;
};
struct node *newNode( int data, struct node *next )
{
struct node *tmp = ( struct node *) malloc( sizeof( struct node ) );
if ( tmp )
{
tmp->data = data;
tmp->next = next;
}
return tmp;
}
/* Function to insert a node at the beginning of the Doubly Linked List */
void push( struct node **head_ref, int data )
{
/* allocate node */
struct node *tmp = newNode( data, *head_ref );
if ( tmp != NULL )
{
*head_ref = tmp;
}
}
int find( struct node *head, int data )
{
while ( head && head->data != data ) head = head->next;
return head != NULL;
}
struct node* list_union( struct node *first, struct node *second )
{
struct node *head = NULL;
struct node **head_ref = &head;
for ( struct node *current = first; current != NULL; current = current->next )
{
struct node *tmp = newNode( current->data, NULL );
if ( tmp != NULL )
{
*head_ref = tmp;
head_ref = &( *head_ref )->next;
}
}
for ( struct node *current = second; current != NULL; current = current->next )
{
if ( !find( first, current->data ) )
{
struct node *tmp = newNode( current->data, NULL );
if ( tmp != NULL )
{
*head_ref = tmp;
head_ref = &( *head_ref )->next;
}
}
}
return head;
}
void printList( struct node *node )
{
for ( ; node != NULL; node = node->next )
{
printf( "%d ", node->data );
}
printf("\n");
}
/* Drier program to test above function */
int main( void )
{
struct node *first = NULL;
struct node *second = NULL;
struct node *union2 = NULL;
// create first list 7->5->9->4->6
push( &first, 6 );
push( &first, 4 );
push( &first, 9 );
push( &first, 5 );
push( &first, 7 );
printf( "First list is: " );
printList( first );
push( &second, 6 );
push( &second, 4 );
push( &second, 9 );
push( &second, 11 );
push( &second, 12 );
printf( "second list is: " );
printList( second );
union2 = list_union( first, second );
printf( "Union of 2 lists is: " );
printList( union2 );
// Here you should call a function that frees all the memory allocated for the lists
}
The program output is
First list is: 7 5 9 4 6
second list is: 12 11 9 4 6
Union of 2 lists is: 7 5 9 4 6 12 11
Also you could write function push such a way that it would not add duplicated values to the list.

Related

linked list problem when displaying the list in C

having segmentation error while trying to access nodes
i can create new nodes with my add function after function executes i cant access my nodes. i think they deallocated in memory but i couldnt figure it out.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *nextNode;
};
struct node *head;
void add(int data)
{
struct node *new = (struct node *)malloc(sizeof(struct node));
new->data = data;
new->nextNode = NULL;
struct node *temp1;
temp1 = head;
while (temp1 != NULL)
{
temp1 = temp1->nextNode;
}
temp1 = new;
printf("\nValue of temp1:%d\nValue of new: %d\n",temp1,new);
printf("\nData of temp1:%d\nData of new:%d\n",temp1->data,new->data);
}
void printList()
{
int i = 1;
struct node *tempP;
tempP = head;
while (tempP != NULL)
{
printf("\nData of %dth element is : %d\n", i, tempP->data);
tempP = tempP->nextNode;
i++;
}
}
void main()
{
head = (struct node *)malloc(sizeof(struct node));
head->data = 10;
head->nextNode = NULL;
add(20);
add(30);
add(40);
printList();
}
This code snippet within the function add
struct node *temp1;
temp1 = head;
while (temp1 != NULL)
{
temp1 = temp1->nextNode;
}
temp1 = new;
is wrong. Within it there is changed the local variable temp1. It is not linked with the list.
Also using the conversion specifier %d to output a pointer invokes undefined behavior. You should use conversion specifier %p.
Using your approach to the function definition you could write instead.
void add(int data)
{
struct node *new = malloc( sizeof( *new ) );
new->data = data;
new->nextNode = NULL;
if ( head == NULL )
{
head = new;
}
else
{
struct node *temp1 = head;
while ( temp1->nextNode != NULL)
{
temp1 = temp1->nextNode;
}
temp1->nextNode = new;
}
printf("\nValue of temp1->nextNode:%p\nValue of new: %p\n",
( void * )temp1->nextNode, ( void * )new);
printf("\nData of temp1->nectNode:%d\nData of new:%d\n",
temp1->nextNode->data,new->data);
}
Pay attention to that it is a bad design when functions depend on a global variable as in your case where the functions depend on the global variable head.
And it is also a bad idea when the first node is added to the list bypassing the function add.
And you need check whether a node was successfully allocated.
Also according to the C Standard the function main without parameters shall be declared like
int main( void )
As for me I would declare the pointer to the head node in main like
int main( void )
{
struct node *head = NULL;
// ...
And the function add will look like
int add( struct node **head, int data )
{
struct node *new_node = malloc( sizeof( *new_node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->nextNode = NULL;
while ( *head != NULL ) head = &( *head )->nextNode;
*head = new_node;
}
return success;
}
and called like
struct node *head = NULL;
add( &head, 10 );
add( &head, 20 );
add( &head, 30 );
add( &head, 40 );
In turn the function printList can look like
void printList( const struct node *head )
{
for ( size_t i = 1; head != NULL; head = head->nextNode )
{
printf( "Data of %zuth element is : %d\n", i++, head->data);
}
}
And you need at least to write one more function that will free all the allocated memory.
There were a handful of mistakes in your add() function, which I've highlighted and fixed below:
void add(int data)
{
struct node *new = malloc(sizeof(*new)); // suggested by ryyker
new->data = data;
new->nextNode = NULL;
struct node *temp1 = head; // just keep it short
while (temp1->nextNode != NULL) // temp1 != NULL will always result in it being NULL, last node is the node with NULL as next
{
temp1 = temp1->nextNode;
}
temp1->nextNode = new; // you want the next in the list to be the new node, not reassign the head to a new node. That's a memory leak.
// remember: temp1 == head, and head = new makes head lose the original node and point to the newly created one
printf("\nValue of temp1:%p\nValue of new: %p\n",temp1,new); // %p for pointers
printf("\nData of temp1:%d\nData of new:%d\n",temp1->data,new->data);
}
Output:
Value of temp1:0x55809a4b22a0
Value of new: 0x55809a4b22c0
Data of temp1:10
Data of new:20
Value of temp1:0x55809a4b22c0
Value of new: 0x55809a4b26f0
Data of temp1:20
Data of new:30
Value of temp1:0x55809a4b26f0
Value of new: 0x55809a4b2710
Data of temp1:30
Data of new:40
Data of 1th element is : 10
Data of 2th element is : 20
Data of 3th element is : 30
Data of 4th element is : 40

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

What is wrong with my code for Pairwise swapping of linked list in C?

This is my code for pairswapping:
#include<stdio.h>
#include<stdlib.h>
struct Node{
int data;
struct Node *next;
};
int main(){
struct Node *list, *head;
head = (struct Node *)malloc(sizeof(struct Node));
list = head;
int i;
for(i=0;i<6;i++){
list->data=i;
list->next = (struct Node *)malloc(sizeof(struct Node));
list = list->next;
}
list->next = NULL;
list = head;
while(list->next->next!=NULL){
int temp = list->data;
list->data = list->next->data;
list->next->data = temp;
list = list->next->next;
}
printf("Pair swapped list: ");
while(head->next!=NULL){
printf("%d\n",head->data);
head=head->next;
}
return 0;
}
I have two problems. The main is that this code is giving a runtime error, I don't see why. and second thing is that if I use list = NULL instead of list->next = null and then while(list!=NULL) then it is causing infinite loop. and if the code is kept same, a garbage element is created at end. please help me.
The line causing problem is:
while(list->next->next!=NULL) {
You do not handle when list->next is NULL
So, just replace it with:
while(list->next != NULL && list->next->next != NULL) {
And for the second problem, as pointed by DevSolar, you must control better the list creation:
struct Node *list, *head, *last;
head = list = last = NULL;
for (i=0; i<6; i++)
{
/* create a node */
list = malloc(sizeof *list);
/* if head is not set, set it */
if (NULL == head)
head = list;
/* fill new element */
list->data = i;
list->next = NULL;
/* this new node is the child of the previous */
if (NULL != last)
last->next = list;
/* remember last created node */
last = list;
}
You have 7 nodes -- the head, and the 6 you create in the loop.
Your while checks for list->next->next!=NULL, and at the end of the loop you move list like this: list = list->next->next;
This means your loop runs for:
1st node, swapped with 2nd
3rd node, swapped with 4th
5th node, swapped with 6th.
Then list is set to the 7th node (with list->next being NULL). And your while checks for list->next->next. As stated, list->next is NULL, list->next->next is an illegal memory access (dereferencing NULL).
(Deferring to purplepsycho for what you should do -- I don't copy from other people's answers. ;-) )
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
In this loop
for(i=0;i<6;i++){
list->data=i;
list->next = (struct Node *)malloc(sizeof(struct Node));
list = list->next;
}
list->next = NULL;
there is allocated a redundant node with an inderterminate value of the data member data.
The condition in this while loop
while(list->next->next!=NULL){
int temp = list->data;
list->data = list->next->data;
list->next->data = temp;
list = list->next->next;
}
is wrong and leads to undefined behavior due to this statement at the end of the loop
list = list->next->next;
The condition should be written like
while ( list && list->next )
Using your approach the program can look the following way
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
int main(void)
{
struct Node *list, *head;
const int N = 6;
head = ( struct Node * )malloc( sizeof( struct Node ) );
list = head;
int i = 0;
do
{
list->data = i;
} while ( ++i < N && ( list = list->next = ( struct Node *)malloc( sizeof( struct Node ) ) ) );
list->next = NULL;
printf("Original list: ");
for ( list = head; list; list = list->next )
{
printf( "%d ", list->data );
}
putchar( '\n' );
list = head;
while ( list && list->next )
{
int temp = list->data;
list->data = list->next->data;
list->next->data = temp;
list = list->next->next;
}
printf("Pair swapped list: ");
for ( list = head; list; list = list->next )
{
printf( "%d ", list->data );
}
putchar( '\n' );
return 0;
}
Its output is
Original list: 0 1 2 3 4 5
Pair swapped list: 1 0 3 2 5 4
You can add yourself checks that malloc(s) were successfull.
A more safe program can be written using the variable list of the type struct Node **.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
int main(void)
{
const int N = 6;
struct Node *head;
struct Node **list;
list = &head;
for ( int i = 0; ( i < N ) && ( *list = ( struct Node *)malloc( sizeof( struct Node ) ) ); i++ )
{
if ( *list )
{
( *list )->data = i;
list = &( *list )->next;
}
}
*list = NULL;
printf("Original list: ");
for ( list = &head; *list; list = &( *list )->next )
{
printf( "%d ", ( *list )->data );
}
putchar( '\n' );
list = &head;
while ( *list && ( *list )->next )
{
int temp = ( *list )->data;
( *list )->data = ( *list )->next->data;
( *list )->next->data = temp;
list = &( *list )->next->next;
}
printf("Pair swapped list: ");
for ( list = &head; *list; list = &( *list )->next )
{
printf( "%d ", ( *list )->data );
}
putchar( '\n' );
return 0;
}
Take into account that you should free all allocated memory for the list.
And one more remark. The program does not swap nodes. It swaps values of the data member data of adjacent nodes.:)

inserting a node at the end of linked list recursivly

typedef struct node
{
int a;
struct node *next;
}node;
void generate(struct node **head)
{
int num = 10, i; //the num here is the length
struct node *temp;
for (i = 0; i < num; i++)
{
temp = (struct node*)malloc(sizeof(struct node));
temp->a = 10-i;
if (*head == NULL)
{
*head = temp; //each time add another node to the start
(*head)->next = NULL;
}
else
{
temp->next = *head;
*head = temp;
}
}
}
void addSpecific(node* head,int n)
{
node* temp = NULL;
if (head->next == NULL)
{
temp = (node*)malloc(sizeof(node*)); //allocating memory
(temp)->a = n; //adding the wanted value
(temp)->next = NULL; //making the new node to point to the end
head->next = temp; //and the previous one to point to temp
}
else
{
addSpecific(head->next, n); //if this is not the wanted node we need to move to the next node
}
}
void deleteNode(struct node **head)
{
struct node *temp;
while (*head != NULL)
{
temp = *head;
*head = (*head)->next; //going to the next node
free(temp); //free the allocated memory
}
}
int main()
{
struct node *head = NULL;
generate(&head);
addSpecific(head, 7);
display(head);
deleteNode(&head);
system("PAUSE");
return 0;
}
I was trying to insert new node at the end using recursion, but the free memory (delete) function make an expansion, and I couldn't find the problem. I tried the generating function and adding the node at the end and it worked but the complier alert me for "heap corruption".
The function can look the following way as it is shown in the following demonstrative program
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
int a;
struct node *next;
} node;
void addSpecific( node **head, int n )
{
if ( *head == NULL )
{
*head = malloc( sizeof( node ) ); //allocating memory
( *head )->a = n; //adding the wanted value
( *head )->next = NULL; //making the new node to point to the end
}
else
{
addSpecific( &( *head )->next, n ); //if this is not the wanted node we need to move to the next node
}
}
void display( node *head )
{
for ( ; head != NULL; head = head->next ) printf( "%d ", head->a );
printf( "\n" );
}
int main( void )
{
const int N = 10;
node *head = NULL;
for ( int i = 0; i < N; i++ )
{
addSpecific( &head, i );
display( head );
}
return 0;
}
The program output is
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
0 1 2 3 4 5
0 1 2 3 4 5 6
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8 9
As for the function deleteNode then it can look for example the following way
void deleteNode( node **head )
{
for ( node *current = *head; current != NULL; )
{
node *temp = current;
current = current->next; //going to the next node
free( temp ); //free the allocated memory
}
*head = NULL;
}
As for this implementation of the function
void deleteNode( node **head )
{
while ( *head != NULL )
{
node *temp = *head;
head = &( *head )->next; //going to the next node
free( temp ); //free the allocated memory
}
}
then it has undefined behavior because it tries to access a data member of the structure object that was already deleted.
Or you can make the function recursive. For example
void deleteNode( node **head )
{
if ( *head != NULL )
{
deleteNode( &( *head )->next );
free( *head );
*head = NULL;
}
}
A bit off-topic, but it is quite convenient to maintain single-linked lists with two pointers, rather than one. This way you can prepend and append the list in O(1) without having to use recursion. E.g.:
struct Node
{
struct Node* next;
};
struct List
{
struct Node *head, **tail;
};
void List_init(struct List* list) {
list->head = 0;
list->tail = &list->head;
}
void List_append(struct List* list, struct Node* node) {
node->next = 0;
*list->tail = node;
list->tail = &node->next;
}
void List_prepend(struct List* list, struct Node* node) {
node->next = list->head;
list->head = node;
if(list->tail == &list->head)
list->tail = &node->next;
}
void List_remove(struct List* list, struct Node* node) {
struct Node *cur = list->head, **prev = &list->head;
while(cur && cur != node) {
prev = &cur->next;
cur = cur->next;
}
if(cur) {
if(!(*prev = node->next))
list->tail = prev;
}
}
# For reference:
#
# SinglyLinkedListNode:
# int data
# SinglyLinkedListNode next
def insertNodeAtTail(node, data):
if node is None:
last = SinglyLinkedListNode(node_data=data)
last.next = None
return last
if node.next is None:
last = SinglyLinkedListNode(node_data=data)
last.next = None
node.next = last
return node
node.next = insertNodeAtTail(node.next, data)
return node

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