Problem Statement
Given two linked lists which are sorted in increasing order. Merge both lists into a single linked list which is also sorted in increasing order.
Example
Input :
List1: 1->2->4->6->9
List2: 3->4->7->8
Output:
New List: 1->2->3->4->4->6->7->8->9
Explanation
As we can see that if we merge both lists and arrange them in increasing order, it will become 1->2->3->4->4->6->7->8->9.
Constraints
$1 <= |List1| <= 10^6$ (1 <= Size of the first linked list <= $10^6$)
$1 <= |List2| <= 10^6$ (1 <= Size of the second linked list <= $10^6$)
$1 <= \text{Node.data} <= 10^6$ (1 <= Value of the Nodes <= $10^6$)
Approach 1 (Using Recursion)
In this approach, we will use Recursion to merge two sorted linked lists. This is one of the easiest approaches to solving this problem. The main intuition behind the approach is that we can keep the track of current nodes in both lists through the recursive function by passing the current nodes as a parameter. The node with the lesser node value will be updated in the recursive call each time. This will lead to the merging of two lists.
Algorithm
- Create a new Node named
result - Check if the
head1is empty, and returnhead2 - Check if
head2is empty, returnhead1 - Now find the node which has the smaller value (
head1orhead2) - Update the
resultwith that node and call the recursive function accordingly - Finally, return the
result
C++ Implementation
#include <bits/stdc++.h>
using namespace std;
class Node
{
public:
int data;
Node* next;
};
Node* MergeSortedLists(Node* head1, Node* head2)
{
Node* result = NULL;
if (head1 == NULL)
return(head2);
else if (head2 == NULL)
return(head1);
if (head1->data <= head2->data)
{
result = head1;
result->next = MergeSortedLists(head1->next, head2);
}
else
{
result = head2;
result->next = MergeSortedLists(head1, head2->next);
}
return(result);
}
void insert(Node** head_ref, int new_data) {
Node* newNode = new Node();
newNode->data = new_data;
newNode->next = (*head_ref);
(*head_ref) = newNode;
}
void printNodes(Node *node) {
while (node!=NULL) {
cout<<node->data<<" ";
node = node->next;
}
}
int main()
{
Node* result = NULL;
Node* head1 = NULL;
Node* head2 = NULL;
insert(&head1, 9);
insert(&head1, 6);
insert(&head1, 4);
insert(&head1, 2);
insert(&head1, 1);
insert(&head2, 8);
insert(&head2, 7);
insert(&head2, 4);
insert(&head2, 3);
result = MergeSortedLists(head1, head2);
printNodes(result);
return 0;
}
Output
1 2 3 4 4 6 7 8 9
Java Implementation
import java.util.*;
class Node
{
int data;
Node next;
Node(int d) {data = d;
next = null;}
}
class Main
{
Node head;
public void addToTheLast(Node node)
{
if (head == null)
{
head = node;
}
else
{
Node temp = head;
while (temp.next != null)
temp = temp.next;
temp.next = node;
}
}
void printList()
{
Node temp = head;
while (temp != null)
{
System.out.print(temp.data + " ");
temp = temp.next;
}
System.out.println();
}
public static void main(String args[])
{
Main head1 = new Main();
Main head2 = new Main();
head1.addToTheLast(new Node(1));
head1.addToTheLast(new Node(2));
head1.addToTheLast(new Node(4));
head1.addToTheLast(new Node(6));
head1.addToTheLast(new Node(9));
head2.addToTheLast(new Node(3));
head2.addToTheLast(new Node(4));
head2.addToTheLast(new Node(7));
head2.addToTheLast(new Node(8));
head1.head = new Mergesortedlists().MergeSortedLists(head1.head, head2.head);
head1.printList();
}
}
class Mergesortedlists
{
public Node MergeSortedLists(Node head1, Node head2)
{
if(head1 == null) return head2;
if(head2 == null) return head1;
if(head1.data < head2.data)
{
head1.next = MergeSortedLists(head1.next, head2);
return head1;
}
else
{
head2.next = MergeSortedLists(head1, head2.next);
return head2;
}
}
}
Output
1 2 3 4 4 6 7 8 9
Python Implementation
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def printList(self):
temp = self.head
while temp:
print(temp.data, end=" ")
temp = temp.next
def insert(self, newData):
newNode = Node(newData)
if self.head is None:
self.head = newNode
return
last = self.head
while last.next:
last = last.next
last.next = newNode
def mergeSortedLists(head1, head2):
temp = None
if head1 is None:
return head2
if head2 is None:
return head1
if head1.data <= head2.data:
temp = head1
temp.next = mergeSortedLists(head1.next, head2)
else:
temp = head2
temp.next = mergeSortedLists(head1, head2.next)
# return the temp list.
return temp
# Create 2 lists
head1 = LinkedList()
head2 = LinkedList()
head1.insert(1)
head1.insert(2)
head1.insert(4)
head1.insert(6)
head1.insert(9)
head2.insert(3)
head2.insert(4)
head2.insert(7)
head2.insert(8)
head1.head = mergeSortedLists(head1.head, head2.head)
head1.printList()
Output
1 2 3 4 4 6 7 8 9
Complexity Analysis
Time Complexity Analysis
In this algorithm, we are using recursion to merge two sorted linked lists, and the recursion will use the time complexity equal to the sum of lengths of both the list, i.e. O(N+M) or in general we can consider it as O(N) time complexity
So the total worst-case time complexity for this approach to merge two sorted linked lists is O(N) + O(M) = O(N+M) = O(N)
Space Complexity Analysis
In this approach, we are using recursion and the recursion will take space complexity equal to the sum of lengths of both the list, i.e. O(N+M) or in general we can consider it as O(N) space complexity
Time Complexity: O(N)
Space Complexity: O(N)
Approach 2 (Using Temporary Dummy Node)
In this approach, we will use a temporary dummy node as a start of the resultant list. The main intuition behind this approach is that first we will create a dummy node and we will add the new nodes at its rear end, which will be created by comparing the current nodes of both the lists i.e. the new node will be created with a smaller node value among both lists, finally, we will return the dummy.next, which will be the final result.
Algorithm
- Create two new Nodes named
dummyandresult - Initialize
resultas&dummy(initializingresultwith the address of the dummy node). - Initialize
dummy.nextwith null - If any of the
head1orhead2is null, then update theresult‘s next pointer with the other node and break out of the loop. - Now find the node which has the smaller value (
head1orhead2) - Update the
result‘s next pointer with that node and move that node one step forward. - Finally return the dummy’s next pointer.
C++ Implementation
#include <bits/stdc++.h>
using namespace std;
class Node
{
public:
int data;
Node* next;
};
void MoveNode(Node** destRef, Node** sourceRef)
{
Node* newNode = *sourceRef;
assert(newNode != NULL);
*sourceRef = newNode->next;
newNode->next = *destRef;
*destRef = newNode;
}
Node* MergeSortedLists(Node* head1, Node* head2)
{
Node dummy;
Node* result = &dummy;
dummy.next = NULL;
while (1)
{
if (head1 == NULL)
{
result->next = head2;
break;
}
else if (head2 == NULL)
{
result->next = head1;
break;
}
if (head1->data <= head2->data)
MoveNode(&(result->next), &head1);
else
MoveNode(&(result->next), &head2);
result = result->next;
}
return(dummy.next);
}
void insert(Node** head_ref, int new_data) {
Node* newNode = new Node();
newNode->data = new_data;
newNode->next = (*head_ref);
(*head_ref) = newNode;
}
void printNodes(Node *node) {
while (node!=NULL) {
cout<<node->data<<" ";
node = node->next;
}
}
int main()
{
Node* result = NULL;
Node* head1 = NULL;
Node* head2 = NULL;
insert(&head1, 9);
insert(&head1, 6);
insert(&head1, 4);
insert(&head1, 2);
insert(&head1, 1);
insert(&head2, 8);
insert(&head2, 7);
insert(&head2, 4);
insert(&head2, 3);
result = MergeSortedLists(head1, head2);
printNodes(result);
return 0;
}
Output
1 2 3 4 4 6 7 8 9
Java Implementation
import java.util.*;
class Node
{
int data;
Node next;
Node(int d) {data = d;
next = null;}
}
class Main
{
Node head;
public void addToTheLast(Node node)
{
if (head == null)
{
head = node;
}
else
{
Node temp = head;
while (temp.next != null)
temp = temp.next;
temp.next = node;
}
}
void printList()
{
Node temp = head;
while (temp != null)
{
System.out.print(temp.data + " ");
temp = temp.next;
}
System.out.println();
}
public static void main(String args[])
{
Main head1 = new Main();
Main head2 = new Main();
head1.addToTheLast(new Node(1));
head1.addToTheLast(new Node(2));
head1.addToTheLast(new Node(4));
head1.addToTheLast(new Node(6));
head1.addToTheLast(new Node(9));
head2.addToTheLast(new Node(3));
head2.addToTheLast(new Node(4));
head2.addToTheLast(new Node(7));
head2.addToTheLast(new Node(8));
head1.head = new Mergesortedlists().MergeSortedLists(head1.head,head2.head);
head1.printList();
}
}
class Mergesortedlists
{
public Node MergeSortedLists(Node head1, Node head2)
{
Node dummyNode = new Node(0);
Node result = dummyNode;
while(true)
{
if(head1 == null)
{
result.next = head2;
break;
}
if(head2 == null)
{
result.next = head1;
break;
}
if(head1.data <= head2.data)
{
result.next = head1;
head1 = head1.next;
}
else
{
result.next = head2;
head2 = head2.next;
}
result = result.next;
}
return dummyNode.next;
}
}
Output
1 2 3 4 4 6 7 8 9
Python Implementation
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def printList(self):
temp = self.head
while temp:
print(temp.data, end=" ")
temp = temp.next
def insert(self, newData):
newNode = Node(newData)
if self.head is None:
self.head = newNode
return
last = self.head
while last.next:
last = last.next
last.next = newNode
def mergeSortedLists(head1, head2):
dummyNode = Node(0)
result = dummyNode
while True:
if head1 is None:
result.next = head2
break
if head2 is None:
result.next = head1
break
if head1.data <= head2.data:
result.next = head1
head1 = head1.next
else:
result.next = head2
head2 = head2.next
result = result.next
return dummyNode.next
# Create 2 lists
head1 = LinkedList()
head2 = LinkedList()
head1.insert(1)
head1.insert(2)
head1.insert(4)
head1.insert(6)
head1.insert(9)
head2.insert(3)
head2.insert(4)
head2.insert(7)
head2.insert(8)
head1.head = mergeSortedLists(head1.head, head2.head)
head1.printList()
Output
1 2 3 4 4 6 7 8 9
Complexity Analysis
Time Complexity Analysis
In this algorithm, we are running a loop while either of the head1 or head2 will become null which will take time complexity equal to the minimum of lengths of both the list, i.e. min(O(N+M)) or in general we can consider it as O(N) time complexity
So the total worst-case time complexity for this approach to merge two sorted linked lists is min(O(N), O(M)) = O(N)
Space Complexity Analysis
In this approach we are just using two variables i.e. Nodes to store the pointers, so we are using constant extra space and we can consider it as O(1) space complexity
Time Complexity: O(N)
Space Complexity: O(1)
Approach 3 (Using Local References)
In this approach, we will use a local reference to store the pointers by their address, so that the changes which we will make in the pointers are reflected in the original resultant node. The main intuition behind this approach is that we will create a pointer to the node which points to the last node and initialize it with the result, which is initialized with null. After every comparison, we will update this last pointer, and we will move to its next, and automatically our result will also be updated.
Algorithm
- Create two new Nodes named
lastptrandresult. - Initialize the
resultas null andlastptras&result(initializinglastptrwith the address of theresultnode). - If any of the
head1orhead2is null, then updatelastptrpointer with the other node and break out of the loop. - Now find the node which has the smaller value (
head1orhead2). - Update the lastref pointer with that node and move that node one step forward.
- Move the lastref pointer one step forward.
- Finally return the
resultnode.
C++ Implementation
#include <bits/stdc++.h>
using namespace std;
class Node
{
public:
int data;
Node* next;
};
void MoveNode(Node** destRef, Node** sourceRef)
{
Node* newNode = *sourceRef;
assert(newNode != NULL);
*sourceRef = newNode->next;
newNode->next = *destRef;
*destRef = newNode;
}
Node* MergeSortedLists(Node* head1, Node* head2)
{
Node* result = NULL;
Node** lastptr = &result;
while (1) {
if (head1 == NULL) {
*lastptr = head2;
break;
}
else if (head2 == NULL) {
*lastptr = head1;
break;
}
if (head1->data <= head2->data)
MoveNode(lastptr, &head1);
else
MoveNode(lastptr, &head2);
lastptr = &((*lastptr)->next);
}
return (result);
}
void insert(Node** head_ref, int new_data) {
Node* newNode = new Node();
newNode->data = new_data;
newNode->next = (*head_ref);
(*head_ref) = newNode;
}
void printNodes(Node *node) {
while (node!=NULL) {
cout<<node->data<<" ";
node = node->next;
}
}
int main()
{
Node* result = NULL;
Node* head1 = NULL;
Node* head2 = NULL;
insert(&head1, 9);
insert(&head1, 6);
insert(&head1, 4);
insert(&head1, 2);
insert(&head1, 1);
insert(&head2, 8);
insert(&head2, 7);
insert(&head2, 4);
insert(&head2, 3);
result = MergeSortedLists(head1, head2);
printNodes(result);
return 0;
}
Output
1 2 3 4 4 6 7 8 9
Java Implementation
import java.util.*;
class Node
{
int data;
Node next;
Node(int d) {data = d;
next = null;}
}
class Main
{
Node head;
public void addToTheLast(Node node)
{
if (head == null)
{
head = node;
}
else
{
Node temp = head;
while (temp.next != null)
temp = temp.next;
temp.next = node;
}
}
void printList()
{
Node temp = head;
while (temp != null)
{
System.out.print(temp.data + " ");
temp = temp.next;
}
System.out.println();
}
public static void main(String args[])
{
Main head1 = new Main();
Main head2 = new Main();
head1.addToTheLast(new Node(1));
head1.addToTheLast(new Node(2));
head1.addToTheLast(new Node(4));
head1.addToTheLast(new Node(6));
head1.addToTheLast(new Node(9));
head2.addToTheLast(new Node(3));
head2.addToTheLast(new Node(4));
head2.addToTheLast(new Node(7));
head2.addToTheLast(new Node(8));
head1.head = new Mergesortedlists().MergeSortedLists(head1.head,head2.head);
head1.printList();
}
}
class Mergesortedlists
{
public Node MergeSortedLists(Node head1, Node head2)
{
Node result = new Node(0);
Node lastptr = result;
while(true)
{
if(head1 == null)
{
lastptr.next = head2;
break;
}
if(head2 == null)
{
lastptr.next = head1;
break;
}
if(head1.data <= head2.data)
{
lastptr.next = head1;
head1 = head1.next;
}
else
{
lastptr.next = head2;
head2 = head2.next;
}
lastptr = lastptr.next;
}
return result.next;
}
}
Output
1 2 3 4 4 6 7 8 9
Python Implementation
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def printList(self):
temp = self.head
while temp:
print(temp.data, end=" ")
temp = temp.next
def insert(self, newData):
newNode = Node(newData)
if self.head is None:
self.head = newNode
return
last = self.head
while last.next:
last = last.next
last.next = newNode
def mergeSortedLists(head1, head2):
result = Node(0)
lastptr = result
while True:
if head1 is None:
lastptr.next = head2
break
if head2 is None:
lastptr.next = head1
break
if head1.data <= head2.data:
lastptr.next = head1
head1 = head1.next
else:
lastptr.next = head2
head2 = head2.next
lastptr = lastptr.next
return result.next
# Create 2 lists
head1 = LinkedList()
head2 = LinkedList()
head1.insert(1)
head1.insert(2)
head1.insert(4)
head1.insert(6)
head1.insert(9)
head2.insert(3)
head2.insert(4)
head2.insert(7)
head2.insert(8)
head1.head = mergeSortedLists(head1.head, head2.head)
head1.printList()
Output
1 2 3 4 4 6 7 8 9
Complexity Analysis
Time Complexity Analysis
In this algorithm, we are running a loop while either of the head1 or head2 will become null which will take time complexity equal to the minimum of lengths of both the list, i.e. min(O(N+M)) or in general we can consider it as O(N) time complexity
So the total worst-case time complexity for this approach to merge two sorted linked lists is min(O(N), O(M)) = O(N)
Space Complexity Analysis
In this approach we are just using two variables i.e. Nodes to store the pointers, so we are using constant extra space and we can consider it as O(1) space complexity
Time Complexity: O(N)
Space Complexity: O(1)
Approach 4 (Reversing the Linked Lists)
In this approach, we will reverse both lists. The main intuition behind this approach is that we will first create two nodes temp and res, and then reverse both lists. We will keep track of our result in the res node and the temp node is used for swapping the res node and the node which is to be added. We will add the head of the current greatest node to the result. By doing this we are building our resultant list in the reverse order.
Algorithm
- Create two new Nodes named
resandtemp. - Initialize both
resandtempwith NULL. - Now run a while loop while
head1andhead2are not null and perform the following steps :- if
head1‘s data>=head2‘s data, then initializetempwithhead1‘s next,head1‘s next withres,reswithhead1, and changehead1totemp. - initialize
tempwithhead2‘s next,head2‘s next withres,reswithhead2, and changehead2totemp.
- if
- Finally return the
resnode.
C++ Implementation
#include <bits/stdc++.h>
using namespace std;
class Node
{
public:
int data;
Node* next;
};
void reverse(Node *&head_ref) {
Node *temp = NULL;
Node *prev = NULL;
Node *current = (head_ref);
while(current != NULL) {
temp = current->next;
current->next = prev;
prev = current;
current = temp;
}
(head_ref) = prev;
}
void MoveNode(Node** destRef, Node** sourceRef)
{
Node* newNode = *sourceRef;
assert(newNode != NULL);
*sourceRef = newNode->next;
newNode->next = *destRef;
*destRef = newNode;
}
Node* MergeSortedLists(Node* head1, Node* head2)
{
Node* res = NULL;
Node* temp = NULL;
reverse(head1);
reverse(head2);
while (head1 and head2) {
if(head1->data>=head2->data){
temp = head1->next;
head1->next = res;
res = head1;
head1=temp;
}
else{
temp = head2->next;
head2->next = res;
res = head2;
head2 = temp;
}
}
while(head1){
temp = head1->next;
head1->next = res;
res = head1;
head1=temp;
}
while(head2){
temp = head2->next;
head2->next = res;
res = head2;
head2 = temp;
}
return (res);
}
void insert(Node** head_ref, int new_data) {
Node* newNode = new Node();
newNode->data = new_data;
newNode->next = (*head_ref);
(*head_ref) = newNode;
}
void printNodes(Node *node) {
while (node!=NULL) {
cout<<node->data<<" ";
node = node->next;
}
}
int main()
{
Node* result = NULL;
Node* head1 = NULL;
Node* head2 = NULL;
insert(&head1, 9);
insert(&head1, 6);
insert(&head1, 4);
insert(&head1, 2);
insert(&head1, 1);
insert(&head2, 8);
insert(&head2, 7);
insert(&head2, 4);
insert(&head2, 3);
result = MergeSortedLists(head1, head2);
printNodes(result);
return 0;
}
Output
1 2 3 4 4 6 7 8 9
Java Implementation
import java.util.*;
class Node
{
int data;
Node next;
Node(int d) {data = d;
next = null;}
}
class Main
{
Node head;
public Node reverse(Node node)
{
Node prev = null;
Node current = node;
Node next = null;
while (current != null) {
next = current.next;
current.next = prev;
prev = current;
current = next;
}
node = prev;
return node;
}
public void addToTheLast(Node node)
{
if (head == null)
{
head = node;
}
else
{
Node temp = head;
while (temp.next != null)
temp = temp.next;
temp.next = node;
}
}
void printList()
{
Node temp = head;
while (temp != null)
{
System.out.print(temp.data + " ");
temp = temp.next;
}
System.out.println();
}
public static void main(String args[])
{
Main head1 = new Main();
Main head2 = new Main();
head1.addToTheLast(new Node(1));
head1.addToTheLast(new Node(2));
head1.addToTheLast(new Node(4));
head1.addToTheLast(new Node(6));
head1.addToTheLast(new Node(9));
head2.addToTheLast(new Node(3));
head2.addToTheLast(new Node(4));
head2.addToTheLast(new Node(7));
head2.addToTheLast(new Node(8));
head1.head = new Mergesortedlists().MergeSortedLists(head1.head,head2.head);
head1.printList();
}
}
class Mergesortedlists
{
Node reverse(Node node)
{
Node prev = null;
Node current = node;
Node next = null;
while (current != null) {
next = current.next;
current.next = prev;
prev = current;
current = next;
}
node = prev;
return node;
}
public Node MergeSortedLists(Node head1, Node head2)
{
Node res = null;
Node temp = null;
head1=reverse(head1);
head2=reverse(head2);
while (head1!=null && head2!=null) {
if(head1.data>=head2.data){
temp = head1.next;
head1.next = res;
res = head1;
head1=temp;
}
else{
temp = head2.next;
head2.next = res;
res = head2;
head2 = temp;
}
}
while(head1!=null){
temp = head1.next;
head1.next = res;
res = head1;
head1=temp;
}
while(head2!=null){
temp = head2.next;
head2.next = res;
res = head2;
head2 = temp;
}
return (res);
}
}
Output
1 2 3 4 4 6 7 8 9
Python Implementation
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def reverse(self):
prev = None
current = self.head
while(current is not None):
next = current.next
current.next = prev
prev = current
current = next
self.head = prev
def insert(self, new_data):
new_node = Node(new_data)
new_node.next = self.head
self.head = new_node
def printList(self):
temp = self.head
while(temp):
print (temp.data,end=" ")
temp = temp.next
def mergeSortedLists(head1, head2):
res = None
temp = None
while (head1!=None and head2!=None):
if(head1.data>=head2.data):
temp = head1.next
head1.next = res
res = head1
head1=temp
else:
temp = head2.next
head2.next = res
res = head2
head2 = temp
while(head1!=None):
temp = head1.next
head1.next = res
res = head1
head1=temp
while(head2!=None):
temp = head2.next
head2.next = res
res = head2
head2 = temp
return res
head1 = LinkedList()
head2 = LinkedList()
head1.insert(1)
head1.insert(2)
head1.insert(4)
head1.insert(6)
head1.insert(9)
head2.insert(3)
head2.insert(4)
head2.insert(7)
head2.insert(8)
head1.head = mergeSortedLists(head1.head, head2.head)
head1.printList()
Output
1 2 3 4 4 6 7 8 9
Complexity Analysis
Time Complexity Analysis
- In the first step, we are reversing both the linked lists which will perform the operations equal to the lengths of the linked lists i.e.
O(N) + O(M) - In the second step, we are running 3 loops, the first loop will perform the operations equal to the minimum of the length of both the lists, the second loop will perform the remaining operations left till the head1 becomes null and the third loop will also perform the remaining operations left till the head2 becomes null.
- So the total time complexity taken in step two will be
O(N)+O(M).
So the total worst-case time complexity for this approach to merge two sorted linked lists is O(N)+O(M)+O(N)+O(M) = 2 * O(N) + 2 * O(M) or in general we can consider it as O(N) time complexity
Space Complexity Analysis
In this approach we are just using two variables i.e. Nodes to store the pointers, so we are using constant extra space and we can consider it as O(1) space complexity
Time Complexity: O(N)
Space Complexity: O(1)
Conclusion
In this quick tutorial, we have discussed 4 different approaches to merge two sorted linked lists.
- In Approach 1, we used simple recursion which took O(N) time complexity and O(N) auxiliary space.
- In Approach 2, we used the dummy node method and returned the dummy.next pointer that took O(N) time complexity and O(1) auxiliary space.
- In Approach 3, we used the local reference variable which took O(N) time complexity and O(1) auxiliary space.
- In approach 4, we reverse the lists that took O(N) time complexity and O(1) auxiliary space.