Trouble merging two linked lists in C - c

I am supposed to write a function to merge (put one at the end of another) two singly linked lists. The user inputs a series of numbers into the console, for example: 1 2 3 4 0 (0 signifies the end of input and is not an element of the list). These numbers are put into the linked list, the list now looks like this: 1 2 3 4. The process repeats again until we have two different linked lists. Then the merging function is called "void merge(struct Node head1, struct Node head2)". Programs ends after the new list is printed.
My thought process would be to first have my pointer point at the end of the first list, then just make a while loop that will go through the other list and make the next element of the first list the current element of the second list.
typedef struct Element Element;
struct Element
{
int data;
Element *next;
};
Element *addNew(int data)
{
Element *newN = (Element*)malloc(sizeof(Element));
newN->data = data;
newN->next = NULL;
return newN;
}
Element *add_on_beginning(Element *head, Element *newN)
{
newN->next = head;
return newN;
}
Element *add_on_end(Element *head, Element *newN)
{
if(head == NULL)
{
return newN;
}
Element *temp = head;
while(temp->next != NULL)
{
temp = temp->next;
}
temp->next = newN;
return head;
}
void printElement(Element *element)
{
printf("%d ", element->data);
}
void printList(Element *head)
{
Element *temp = head;
while(temp != NULL)
{
printElement(temp);
temp = temp->next;
}
}
void merge(Element *head1, Element *head2)
{
Element *temp1 = head1;
Element *temp2 = head2;
while(temp1->next != NULL)
{
temp1 = temp1->next;
}
while(temp2->next != NULL)
{
temp1->next = temp2;
temp2 = temp2->next;
}
}
int main()
{
Element *head1 = NULL;
Element *head2 = NULL;
int arr[1000];
char temp1;
char temp2;
int i = 0;
int j = 0;
printf("Input the first set of elements: \n");
while(temp1 != '\n')
{
scanf("%d%c", &arr[i], &temp1);
if(arr[i] == 0)
{
break;
}
head1 = add_on_end(head1, addNew(arr[i]));
i++;
}
printf("Input the second set of elements: \n");
while(temp2 != '\n')
{
scanf("%d%c", &arr[j], &temp2);
if(arr[j] == 0)
{
break;
}
head2 = add_on_end(head2, addNew(arr[j]));
j++;
}
merge(head1, head2);
printList(head1);
return 0;
}
So for some reason, the function only reads last two elements of the second list.
INPUT:
1 2 3 4 0
5 6 7 8 0
OUTPUT:
1 2 3 4 7 8
The result I'm supposed to get is
INPUT:
1 2 3 4 0
5 6 7 8 0
OUTPUT:
1 2 3 4 5 6 7 8

Think "code reuse".
You've already written the functionality you want. Reuse it...
printList( add_on_end( head1, head2 ) );
You've used malloc() to grab space for your nodes from the heap.
main() exits immediately, but it's good practice to at least acknowledge in a comment that you're not iteratively calling free().
Edit printList() could be shifted into main() and its "final traversal" of the linked list used to make those calls to free().

This function
void merge(Element *head1, Element *head2)
{
Element *temp1 = head1;
Element *temp2 = head2;
while(temp1->next != NULL)
{
temp1 = temp1->next;
}
while(temp2->next != NULL)
{
temp1->next = temp2;
temp2 = temp2->next;
}
}
is invalid.
First of all it does not change the original pointers head1 and head2 because they are passed to the function by value. So the function deals with copies of the original pointers.
Secondly in the function there is no check whether head1 or head2 is equal to NULL.
The function can be defined the following way
void merge( Element **head1, Element **head2 )
{
if ( *head1 == NULL )
{
*head1 = *head2;
*head2 = NULL;
}
else if ( *head2 != NULL )
{
while ( *head1 != NULL ) head1 = &( *head1 )->next;
for ( ; *head2 != NULL; head2 = &( *head2 )->next )
{
*head1 = *head2;
head1 = &( *head1 )->next;
}
}
}
Pay attention to that there is no need to declare an array to input data in the list.
Also these while loops
char temp1;
char temp2;
int i = 0;
int j = 0;
printf("Input the first set of elements: \n");
while(temp1 != '\n')
//..
and
while(temp2 != '\n')
//...
has undefined behavior because neither temp1 nor temp2 are initialized.

One of your problems is:
while(temp2->next != NULL) {
temp1->next = temp2;
temp2 = temp2->next;
}
You are not updating the value of temp1.
Also, why don't you just instead of this second while do:
temp1->next = temp2;
I mean linked list 2 is properly linked, you just need to link the end of the first list with the beginning of the second.

Related

My function to merge two linked lists is not working properly

I'm supposed to make a function that will merge two sorted singly linked lists.
The user inputs two sets of numbers in the console, for example: 5 3 1 0, which make a linked list, 0 signifies the end of that input and is not a part of that list. Then the lists are sorted, from the smallest to the largest value. After the sorting, elements of the lists are supposed to be added into a new list, one by one. At the end, the newly created list should be printed.
I've tried with a lot of different methods, but the one I liked the most was to have two different pointers to the heads, so p would be a pointer for head1 and q would be a pointer for head2. I start with whichever head value is smaller and move the pointer of that head to the next element. Then I remember that head with the node I'm going to return at the end, and move onto the while loop, where it goes from one list to another.
Okay, I use S to add the elements to my new list, first I start from the lower number between thew two lists, which is in this case 1 and the first list, as soon as I give S its value, I also move pointer p0 to the next element, so now its pointing to 3 (p1). Then I make that S the head of my new list and move onto the while loop. In while loop I check if the last element that was added to my new list was from the first or the second list, depending on the result, let's just say the last element was from the first list (number 1), we move onto the second list. I make S point to q1, q then points to the next element of the second list (q2) and the while loop starts again. The process repeats itself until one of the two pointers is NULL. After the while loop, I have two if statements (one for each pointers in case they point to NULL) where I return the other pointer. Hopefully now it's a bit more clear.
typedef struct Element Element;
struct Element {
int data;
Element *next;
};
Element *addNew(int data) {
Element *newN = (Element*)malloc(sizeof(Element));
newN->data = data;
newN->next = NULL;
return newN;
}
Element *add_on_beginning(Element *head, Element *newN) {
newN->next = head;
return newN;
}
Element *add_on_end(Element *head, Element *newN) {
if (head == NULL) {
return newN;
}
Element *temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newN;
return head;
}
void swap(Element *a, Element *b) {
int tempV;
tempV = a->data;
a->data = b->data;
b->data = tempV;
}
void sortList(Element *head) {
Element *temp;
int swapped;
do {
swapped = 0;
temp = head;
while (temp->next != NULL) {
if (temp->data > temp->next->data) {
swap(temp, temp->next);
swapped = 1;
}
temp = temp->next;
}
} while(swapped);
}
Element *merge(Element *head1, Element *head2, Element *newHead) {
Element *p = head1;
Element *q = head2;
Element *sort = NULL;
if (p == NULL) {
return q;
}
if (q == NULL) {
return p;
}
if (p != NULL && q != NULL) {
if (p->data <= q->data) {
sort = p;
p = sort->next;
} else {
sort = q;
q = sort->next;
}
}
newHead = sort;
while (p != NULL && q != NULL) {
if (sort->next == p->next) {
sort->next = q;
sort = q;
q = sort->next;
} else {
sort->next = p;
sort = p;
p = sort->next;
}
}
if (p == NULL) {
sort->next = q;
}
if (q == NULL) {
sort->next = p;
}
return newHead;
}
void printElement(Element *element) {
printf("%d ", element->data);
}
void printList(Element *head) {
Element *temp = head;
while (temp != NULL) {
printElement(temp);
temp = temp->next;
}
}
int main() {
Element *head = NULL;
Element *head2 = NULL;
Element *head3 = NULL;
char t;
int i;
char p;
int j;
printf("Input the first set of numbers: \n");
while (t != '\n') {
scanf("%d%c", &i, &t);
if (i == 0) {
break;
}
head = add_on_end(head, addNew(i));
}
printf("Input the second set of numbers: \n");
while (p != '\n') {
scanf("%d%c", &j, &p);
if (j == 0) {
break;
}
head2 = add_on_end(head2, addNew(j));
}
sortList(head);
sortList(head2);
head3 = merge(head, head2, head3);
printList(head3);
return 0;
}
The problem I'm having is with merging, it prints out those two lists sorted but not merged with one and other, instead its the first list and right after the second.
So for example:
INPUT:
2 6 4 8 1
7 9 2 3 5
OUTPUT:
1 2 4 6 8 2 3 5 7 9
It should be:
INPUT:
2 6 4 8 1
7 9 2 3 5
OUTPUT:
1 2 2 3 4 5 6 7 8 9
The merge function is too complicated:
the test if (p != NULL && q != NULL) is redundant
in the while loop you do not test the node values, which explains why merge fails.
the third argument newHead is useless.
Here is a modified version:
Element *merge(Element *p, Element *q) {
Element *newHead = NULL;
Element *sort = NULL;
if (p == NULL) {
return q;
}
if (q == NULL) {
return p;
}
if (p->data <= q->data) {
newHead = sort = p;
p = p->next;
} else {
newHead = sort = q;
q = q->next;
}
while (p != NULL && q != NULL) {
if (p->data <= q->data) {
sort = sort->next = p;
p = p->next;
} else {
sort = sort->next = q;
q = q->next;
}
}
if (p == NULL) {
sort->next = q;
}
if (q == NULL) {
sort->next = p;
}
return newHead;
}
Most of the added complexity in OP's code is caused by the need to handle the edge-cases(finding the address of the new head) Edge cases can sometimes be avoided.
Trivial solution using a pointer-to-pointer:
struct thing{
struct thing *next;
int value;
};
struct thing *merge(struct thing *one, struct thing *two)
{
struct thing *result;
struct thing **pp; // will always point to the _pointer_ that will be assigned the next node.
result=NULL;
for(pp = &result; one && two; pp = &(*pp)->next) {
if(one->value <= two->value) {
*pp = one; one = one->next;
}
else {
*pp = two; two = two->next;
}
}
// When we get here, one and/or two will be NULL
*pp = (one) ? one : two;
return result;
}
The same logic, but with an extra dereference instead of the pointer-to-pointer:
struct thing *merge2(struct thing *one, struct thing *two)
{
struct thing dummy;
struct thing *last;
dummy.next=NULL;
for(last = &dummy; one && two; last = last->next) {
if(one->value <= two->value) {
last->next = one; one = one->next;
}
else {
last->next = two; two = two->next;
}
}
last->next = (one) ? one : two;
return dummy.next;
}
Now, the fun fact is,that cc -Wall -omit-frame-pointer -O3 -S llist23.c generates exactly the same code for these two functions.

How to delete node from doubly linked list in c

I am working on doubly linked list in c, I have a doubly linked tepm2 with 20 nodes and I want to delete the node whose word user insert.
struct node {
struct node *prev;
char word[100];
int repeatTime;
struct node *next;
} *h, *temp, *temp1, *temp2;
Each node has unique word.
printf("\n Enter word to delete : ");
scanf("%s", &word);
Delete(word);
int delete(char data[200]) { //unable to delete
if (h == NULL)
return;
temp2 = next = previous = h;
while (temp2->next != NULL) {
if ((strcmp(temp2->word, data) == 0)) {
if (temp2->prev == NULL) {
h = temp2->next;
free(temp2);
return;
} else if (temp2->prev == NULL) {
previous->next = temp2;
free(temp2);
previous->next = NULL;
return;
} else {
previous->next = temp2->next;
next->prev = temp2->next;
}
}
temp2 = temp->next;
}
}
I am been unable to delete the specific node that word user enter
Try this:
int delete(const char *data)
{
struct node *temp = h;
if (h == NULL) return;
while (temp->next != NULL)
{
if (strcmp(temp->word, data) == 0)
{
if (temp->prev != NULL)
{
temp->prev->next = temp->next;
}
if (temp->next != NULL)
{
temp->next->prev = temp->prev;
}
if (h == temp)
{
h = temp->next;
}
free(temp);
return;
}
temp = temp->next;
}
}
First of all I don't think this is right temp2 = next = previous = h;
Now all you have to do is find the node that you want to delete by traversing and than link it's prev node to it's next node i.e. (temp2->prev)->next = next and (temp2->next)->prev = prev and free it.
Now the real issue lies with
1. The first node that has other nodes after it
2. last node that has other nodes preceding it
3. only node
You can simplify all three by converting them into the former problem i.e. node in the middle problem which we've just solved.
For simplifying you can just make the head and tail both NULL.

Delete last two elements from linked list in C

I have this piece of code, it deletes the last element from a linked list. What changes do I have to make so it will delete the last TWO elements of the linked list?
void deletesEnd() {
struct node *temp, *last;
temp = head;
last = temp;
while (temp != NULL && temp->next != NULL) {
last = temp;
temp = temp->next;
}
if (last == temp) {
free(temp);
head = NULL;
} else {
free(last->next);
last->next = NULL;
}
}
The simplest solution to remove the last 2 elements of the list is to call deletesEnd() twice. Note that deletesEnd() should take head as an argument and return the new value. You would delete the last 2 by issuing a nested call:
struct node *deletesEnd(struct node *head) {
struct node *temp, *last;
last = temp = head;
while (temp && temp->next != NULL) {
last = temp;
temp = temp->next;
}
if (last == head) {
free(head);
head = NULL;
} else {
free(last->next);
last->next = NULL;
}
return head;
}
Delete the last element: head = deletesEnd(head);
Delete the last 2 elements: head = deletesEnd(deletesEnd(head));
The simplicity of the design more than compensates for the overhead of enumerating the list twice.
If you absolutely want a specific function, you can extend your approach this way:
struct node *deleteLast2Nodes(struct node *head) {
struct node *temp, *last;
last = temp = head;
while (temp && temp->next != NULL && temp->next->next != NULL) {
last = temp;
temp = temp->next;
}
if (last == head) {
if (head) {
free(head->next);
}
free(head);
head = NULL;
} else {
free(last->next->next);
free(last->next);
last->next = NULL;
}
return head;
}
Here is a demonstrative program that shows how two last nodes can be deleted simultaneously. In fact the function is similar to your function except it checks not only the next node but also the next->next node.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int value;
struct node *next;
} *head;
void push( int value )
{
struct node *tmp = malloc( sizeof( struct node ) );
tmp->value = value;
tmp->next = head;
head = tmp;
}
void display()
{
for ( struct node *current = head; current; current = current->next )
{
printf( "%d ", current->value );
}
}
void deleteLastTwo()
{
struct node *current = head;
struct node *prev = head;
if ( current && current->next )
{
while ( current->next->next )
{
prev = current;
current = current->next;
}
}
if ( current )
{
if ( current->next )
{
free( current->next );
}
if ( prev == current )
{
head = NULL;
}
else
{
prev->next = NULL;
}
free( current );
}
}
int main(void)
{
const int N = 11;
for ( int i = N; i != 0; i-- ) push( i - 1 );
display();
printf( "\n" );
while ( head )
{
deleteLastTwo();
display();
printf( "\n" );
}
return 0;
}
The program output is
0 1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6
0 1 2 3 4
0 1 2
0
Take into account that it is not a good idea when the head node is declared like a global variable. It is better when it can be declared like a local variable. In this case you will need to rewrite the methods of the list because in most cases the current methods will not work correctly.
This logic will delete your last 2 node in singly linked list.
void deletesEnd()
{
struct node *temp, *last;
temp = head;
last = temp;
while (temp->next->next != NULL)
{
last = temp->next;
if(last->next->next!=NULL)
temp = temp->next;
else
break;
}
struct node *ptr=last->next;
last->next=ptr->next;
free(ptr);
temp->next=last->next;
free(last);
}
For fun & education: simple recursive version.
The function return := the number of nodes below us
After the recursion returns, we can decide if we are too close to the tail.
and remove ourselves
because we pass a pointer to pointer, this should also work for lists of size=2 and smaller
unsigned del_tail_n(struct llist **pp, unsigned nn)
{
unsigned pos;
if (!*pp) return 0;
// this recursive call returns 0 iff (*pp)->next is NULL
pos = del_tail_n( &(*pp)->next, nn);
if (pos < nn) {
// free (*pp);
*pp = NULL;
}
return 1+pos;
}
For those who don't like recursion, here is a non-recursive version.
[do note that both versions work for empty lists (*pp == NULL) , or for lists smaller than nn ]
void del_tail_n2(struct llist **pp, unsigned nn)
{
struct llist *p;
/* Advance p pointer n positions down, starting from *pp. */
for (p= *pp; p; p=p->next) {
if (nn-- < 1) break;
}
/* Do a synchronous walk down for both p and *pp, until p is NULL. */
for ( ; p; p=p->next) {
pp = &(*pp)->next;
}
/* Now, *pp is the first node to delete
** Delete it and everything below it.
*/
for ( ;(p = *pp); ){
*pp = p->next;
// free (p);
}
return;
}

deleting a node in the middle of a linked list

I have written a piece of code that uses linked lists. I get the user to enter a couple of numbers and then ask the user to enter the index of the digit he wishes to delete. I did some research and found out that i need to check whether the next node is the one I want to delete, then have 2 temp pointers point to the current node and the next node(which is the one i want to delete), then assign the next node of the first temp pointer to the next node of the second temp pointer then finally free the second temp pointer. Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int item;
struct node *next;
}ListNode;
void print(ListNode *head);
int deleteNode(ListNode **ptrHead, int index);
int main()
{
int n;
int remove;
ListNode *head = NULL;
ListNode *temp = NULL;
printf("Enter a value: ");
scanf("%d", &n);
while (n != -1)
{
if (head == NULL)
{
head = malloc(sizeof(ListNode));
temp = head;
}
else
{
temp->next = malloc(sizeof(ListNode));
temp = temp->next;
}
temp->item = n;
temp->next = NULL;
printf("Enter a value: ");
scanf("%d", &n);
}
printf("Enter index to remove: ");
scanf("%i", &remove);
while (remove != -1)
{
deleteNode(&head, remove);
print(head);
printf("Enter index to remove: ");
scanf("%i", &remove);
}
while (head != NULL)
{
temp = head;
head = head->next;
free(temp);
}
head = NULL;
return 0;
}
int deleteNode(ListNode **ptrHead, int index)
{
int count = 0;
ListNode* temp1 = NULL;
ListNode* temp2 = NULL;
while (count <= index)
{
if (index == 0)
{
temp2 = (*ptrHead)->next;
free((*ptrHead));
(*ptrHead) = temp2;
return 0;
break;
}
if (count+1 == index)//checking for the node ahead
{
temp1 = (*ptrHead);
temp2 = (*ptrHead)->next;//the one to free
temp1->next = temp2->next;
free(temp2);
return 0;
break;
}
(*ptrHead) = (*ptrHead)->next;
count++;
}
return -1;
}
void print(ListNode *head){
if (head == NULL)
{
return;
}
while (head != NULL)
{
printf("%i\n", head->item);
head = head->next;
}
}
So for example if i enter 1 2 3 4 5 -1, the linked list will contain 1 2 3 4 5. Then if i enter 0 for the index to remove, the program will print out 2 3 4 5. This works whether I enter 0 or 1. However, when I enter the indexes 2 and above, it gives me weird outputs like for example if I set the linked list as 1 2 3 4 5, and enter the index 2 to remove, by rights it should output 1 2 4 5, but instead it outputs 2 4 5, I have no idea whats going on, please point me in the right direction.
In deleteNode you use the actual headpointer to traverse the list. As you loop through the list you move the actual head! You should only modify (*ptrHead) when you delete the first element.
I suggest that you copy *ptrHead to a local variable and use the local variable to traverse the list.
I've highlighted the important lines with comments starting with // ***
int deleteNode(ListNode **ptrHead, int index)
{
int count = 0;
ListNode* temp1 = NULL;
ListNode* temp2 = NULL;
ListNode* traverse = *ptrHead; // *** make a copy that we can use to traverse the list
while (count <= index)
{
if (index == 0)
{
temp2 = (*ptrHead)->next;
free((*ptrHead));
(*ptrHead) = temp2; // *** Keep this line as it is to correctly handle deletion of index 0.
return 0;
break;
}
if (count+1 == index)//checking for the node ahead
{
temp1 = traverse; // *** Use local copy of pointer
temp2 = traverse->next;//the one to free // *** Use local copy of pointer
temp1->next = temp2->next;
free(temp2);
return 0;
break;
}
traverse = traverse->next; // *** Use local copy of pointer
count++;
}
return -1;
}
Find the modified deleteNode function (handles boundary conditions also , if we are trying to delete an index which is more then the list length)
int deleteNode(ListNode **ptrHead, int index)
{
int count = 0;
ListNode* temp1 = NULL;
ListNode* temp2 = NULL;
temp1 = (*ptrHead);
while((temp1 != NULL) && (count <= index))
{
if (index == 0)
{
temp2 = temp1->next;
free(temp1);
(*ptrHead) = temp2;
return 0;
}
if ((count+1 == index) && (temp1->next != NULL))
{
ListNode*temp = NULL;
temp = temp1->next;
temp2 = temp->next;
temp1->next = temp2;
free(temp);
return 0;
}
temp1 = temp1->next;
count++;
}
return -1;
}

I'm trying to add numbers into a linked list in ascending order. what can I fix so it'll work? Here's my code:

This code is supposed to put numbers into a linked list in ascending order. This is one function of my program that takes keyboard input(int x) from the user of the program.
node* insert(node *head, int x)
{
node *newPtr;
node *prePtr;
node *currentPtr;
newPtr = malloc(sizeof(node));
if(newPtr != NULL){
newPtr->value = x;
newPtr->next = NULL;
prePtr = NULL;
currentPtr = head;
while(currentPtr != NULL && x > currentPtr->value){
prePtr = currentPtr;
currentPtr = currentPtr->next;
}
if(prePtr == NULL){
newPtr->next = head;
head = newPtr;
}
else{
prePtr->next = newPtr;
newPtr->next = currentPtr;
}
}
}
int main(void)//calling input function in main
{
node *head = NULL;
int x=0;
while(x!=-1){
printf("?: ");
scanf("%d", &x);
head=insert(head,x);
print(head);
printf("\n");
}
return 0;
}
//It seems to only put a few numbers in, then it resets
The main() function asks for a numerical input, and sends that input into the insert function which is supposed to put the numbers in ascending order. Sample output:
$ gcc prelab2.c
$ ./a.out
?: 4
4 -> NULL
?: 3
3 -> 4 -> NULL
?: 9
3 -> 4 -> 9 -> NULL
?: 7
3 -> 4 -> 7 -> 9 -> NULL
?: 2
2 -> 3 -> 4 -> 7 -> 9 -> NULL
?: -1
There is only a small mistake. In main() method
head=insert(head,x);
your Insert method return nothing (NULL). so your head is never changed it is always NULL;
return head;
Just return head in insert method and it will work fine.
Try the following changes it should work fine.
node* insert(node *head, int x)
{
node *newPtr;
node *prePtr;
node *currentPtr;
newPtr = malloc(sizeof(node));
if(newPtr != NULL)
{
newPtr->value = x;
newPtr->next = NULL;
// check if the linked list is empty add the node directly and return
if(head == NULL)
{
head = newptr;
return head;
}
else
{
currentPtr = head;
while(x > currentPtr->value && currentPtr->next != NULL)
{
currentPtr = currentPtr->next;
}
// make the new node point where current next is pointing
newPtr->next = currentPtr->next;
// make the current point to new node
currentPtr->next = newPtr;
}
return head;
}
else
return NULL; // signifying malloc failed
}
EDIT: corrected the code missed out a condition check while copying

Resources