Given a singly linked list of integers, the task is to sort it using iterative merge sort.
Merge Sort is often preferred for sorting a linked list. It is discussed here. However, the method discussed above uses Stack for storing recursion calls. This may consume a lot of memory if the linked list to be sorted is too large. Hence, a purely iterative method for Merge Sort with no recursive calls is discussed in this post.
We use bottom-up approach of Merge Sort in this post. We know that Merge Sort first merges two items, then 4 items and so on. The idea is to use an integer variable to store the gap to find the midpoint around which the linked list needs to be sorted. So the problem reduces to merging two sorted Linked List which is discussed here. However, we do not use an additional list to keep the merged list. Instead we merge the lists within itself. The gap is incremented exponentially by 2 in each iteration and the process is repeated.
Implementation:
// Iterative C++ program to do merge sort on // linked list #include <iostream> using namespace std;
/* Structure of the Node */ struct Node {
int data;
struct Node* next;
}; /* Function to calculate length of linked list */ int length( struct Node* current)
{ int count = 0;
while (current != NULL) {
current = current->next;
count++;
}
return count;
} /* Merge function of Merge Sort to Merge the two sorted parts of the Linked List. We compare the next value of start1 and
current value of start2 and insert start2 after start1 if
it's smaller than next value of start1. We do this until
start1 or start2 end. If start1 ends, then we assign next
of start1 to start2 because start2 may have some elements
left out which are greater than the last value of start1.
If start2 ends then we assign end2 to end1. This is necessary
because we use end2 in another function (mergeSort function)
to determine the next start1 (i.e) start1 for next
iteration = end2->next */
void merge( struct Node** start1, struct Node** end1,
struct Node** start2, struct Node** end2)
{ // Making sure that first node of second
// list is higher.
struct Node* temp = NULL;
if ((*start1)->data > (*start2)->data) {
swap(*start1, *start2);
swap(*end1, *end2);
}
// Merging remaining nodes
struct Node* astart = *start1, *aend = *end1;
struct Node* bstart = *start2, *bend = *end2;
struct Node* bendnext = (*end2)->next;
while (astart != aend && bstart != bendnext) {
if (astart->next->data > bstart->data) {
temp = bstart->next;
bstart->next = astart->next;
astart->next = bstart;
bstart = temp;
}
astart = astart->next;
}
if (astart == aend)
astart->next = bstart;
else
*end2 = *end1;
} /* MergeSort of Linked List The gap is initially 1. It is incremented as
2, 4, 8, .. until it reaches the length of the
linked list. For each gap, the linked list is
sorted around the gap.
The prevend stores the address of the last node after
sorting a part of linked list so that it's next node
can be assigned after sorting the succeeding list.
temp is used to store the next start1 because after
sorting, the last node will be different. So it
is necessary to store the address of start1 before
sorting. We select the start1, end1, start2, end2 for
sorting. start1 - end1 may be considered as a list
and start2 - end2 may be considered as another list
and we are merging these two sorted list in merge
function and assigning the starting address to the
previous end address. */
void mergeSort( struct Node** head)
{ if (*head == NULL)
return ;
struct Node* start1 = NULL, *end1 = NULL;
struct Node* start2 = NULL, *end2 = NULL;
struct Node* prevend = NULL;
int len = length(*head);
for ( int gap = 1; gap < len; gap = gap*2) {
start1 = *head;
while (start1) {
// If this is first iteration
bool isFirstIter = 0;
if (start1 == *head)
isFirstIter = 1;
// First part for merging
int counter = gap;
end1 = start1;
while (--counter && end1->next)
end1 = end1->next;
// Second part for merging
start2 = end1->next;
if (!start2)
break ;
counter = gap;
end2 = start2;
while (--counter && end2->next)
end2 = end2->next;
// To store for next iteration.
Node *temp = end2->next;
// Merging two parts.
merge(&start1, &end1, &start2, &end2);
// Update head for first iteration, else
// append after previous list
if (isFirstIter)
*head = start1;
else
prevend->next = start1;
prevend = end2;
start1 = temp;
}
prevend->next = start1;
}
} /* Function to print the Linked List */ void print( struct Node** head)
{ if ((*head) == NULL)
return ;
struct Node* temp = *head;
while (temp != NULL) {
printf ( "%d " , temp->data);
temp = temp->next;
}
printf ( "\n" );
} /* Given a reference (pointer to pointer) to the head of a list
and an int, push a new node on
the front of the list. */
void push( struct Node** head_ref,
int new_data)
{ struct Node* new_node = new Node;
new_node->data = new_data;
new_node->next = (*head_ref);
(*head_ref) = new_node;
} int main()
{ // start with empty list
struct Node* head = NULL;
// create linked list
// 1->2->3->4->5->6->7
push(&head, 7);
push(&head, 6);
push(&head, 5);
push(&head, 4);
push(&head, 3);
push(&head, 2);
push(&head, 1);
mergeSort(&head);
print(&head);
} |
// Iterative Java program to do merge sort on // linked list class GFG
{ /* Structure of the Node */ static class Node
{ int data;
Node next;
}; /* Function to calculate length of linked list */ static int length(Node current)
{ int count = 0 ;
while (current != null )
{
current = current.next;
count++;
}
return count;
} /* Merge function of Merge Sort to Merge the two sorted parts of the Linked List. We compare the next value of start1 and current value of start2 and insert start2 after start1 if it's smaller than next value of start1. We do this until start1 or start2 end. If start1 ends, then we assign next of start1 to start2 because start2 may have some elements left out which are greater than the last value of start1. If start2 ends then we assign end2 to end1. This is necessary because we use end2 in another function (mergeSort function) to determine the next start1 (i.e) start1 for next iteration = end2.next */ static Node merge(Node start1, Node end1,
Node start2, Node end2)
{ // Making sure that first node of second
// list is higher.
Node temp = null ;
if ((start1).data > (start2).data)
{
Node t = start1;
start1 = start2;
start2 = t;
t = end1;
end1 = end2;
end2 = t;
}
// Merging remaining nodes
Node astart = start1, aend = end1;
Node bstart = start2, bend = end2;
Node bendnext = (end2).next;
while (astart != aend && bstart != bendnext)
{
if (astart.next.data > bstart.data)
{
temp = bstart.next;
bstart.next = astart.next;
astart.next = bstart;
bstart = temp;
}
astart = astart.next;
}
if (astart == aend)
astart.next = bstart;
else
end2 = end1;
return start1;
} /* MergeSort of Linked List The gap is initially 1. It is incremented as 2, 4, 8, .. until it reaches the length of the linked list. For each gap, the linked list is sorted around the gap. The prevend stores the address of the last node after sorting a part of linked list so that it's next node can be assigned after sorting the succeeding list. temp is used to store the next start1 because after sorting, the last node will be different. So it is necessary to store the address of start1 before sorting. We select the start1, end1, start2, end2 for sorting. start1 - end1 may be considered as a list and start2 - end2 may be considered as another list and we are merging these two sorted list in merge function and assigning the starting address to the previous end address. */ static Node mergeSort(Node head)
{ if (head == null )
return head;
Node start1 = null , end1 = null ;
Node start2 = null , end2 = null ;
Node prevend = null ;
int len = length(head);
for ( int gap = 1 ; gap < len; gap = gap* 2 )
{
start1 = head;
while (start1 != null )
{
// If this is first iteration
boolean isFirstIter = false ;
if (start1 == head)
isFirstIter = true ;
// First part for merging
int counter = gap;
end1 = start1;
while (--counter > 0 && end1.next != null )
end1 = end1.next;
// Second part for merging
start2 = end1.next;
if (start2 == null )
break ;
counter = gap;
end2 = start2;
while (--counter > 0 && end2.next != null )
end2 = end2.next;
// To store for next iteration.
Node temp = end2.next;
// Merging two parts.
merge(start1, end1, start2, end2);
// Update head for first iteration, else
// append after previous list
if (isFirstIter)
head = start1;
else
prevend.next = start1;
prevend = end2;
start1 = temp;
}
prevend.next = start1;
}
return head;
} /* Function to print the Linked List */ static void print(Node head)
{ if ((head) == null )
return ;
Node temp = head;
while (temp != null )
{
System.out.printf( "%d " , temp.data);
temp = temp.next;
}
System.out.printf( "\n" );
} /* Given a reference (pointer to pointer) to the head of a list and an int, push a new node on the front of the list. */ static Node push( Node head_ref,
int new_data)
{ Node new_node = new Node();
new_node.data = new_data;
new_node.next = (head_ref);
(head_ref) = new_node;
return head_ref;
} public static void main(String args[])
{ // start with empty list
Node head = null ;
// create linked list
// 1.2.3.4.5.6.7
head = push(head, 7 );
head = push(head, 6 );
head = push(head, 5 );
head = push(head, 4 );
head = push(head, 3 );
head = push(head, 2 );
head = push(head, 1 );
head = mergeSort(head);
print(head);
} } // This code is contributed by Arnab Kundu |
# Iterative Python3 program to do merge sort on # linked list class Node:
"""Structure of the Node."""
def __init__( self , data: int ):
self .data = data
self . next = None
class LinkedList:
"""Encapsulate each left/right part's nodes in order to pass them as
pointers. Without this workaround, the code would only work for a
reverse-ordered list."""
head: Node
tail: Node
def __init__( self , head = None , tail = None ):
self .start = head
self .end = tail
def list_length(current: Node):
"""Function to calculate length of linked list."""
count = 0 ;
while (current ! = None ):
current = current. next ;
count + = 1
return count;
def merge(left: LinkedList, right: LinkedList) - > None :
"""Merge the two sorted parts of the original linked list in order.
Merge function of Merge Sort to Merge the two sorted parts of the
Linked List. We compare the next value of start1 and current value of
start2 and insert start2 after start1 if it's smaller than next value
of start1. We do this until start1 or start2 end. If start1 ends, then
we assign next of start1 to start2 because start2 may have some elements
left out which are greater than the last value of start1. If start2 ends
then we assign end2 to end1. This is necessary because we use end2 in
another function (mergeSort function) to determine the next start1 (i.e)
start1 for next iteration = end2.next"""
# Ensure the first node of the second list is higher.
if left.start.data > right.start.data:
left.start, right.start = right.start, left.start
left.end, right.end = right.end, left.end
# Merge all remaining nodes.
astart = left.start
aend = left.end
bstart = right.start
bendnext = right.end. next
while astart ! = aend and bstart ! = bendnext:
if astart. next .data > bstart.data:
temp = bstart. next
bstart. next = astart. next
astart. next = bstart
bstart = temp
astart = astart. next
if astart = = aend:
astart. next = bstart
else :
right.end = left.end
def mergeSort(head: LinkedList) - > None :
"""MergeSort of Linked List The gap is initially 1. It is incremented as
2, 4, 8, .. until it reaches the length of the linked list. For each gap,
the linked list is sorted around the gap. The prevend stores the address
of the last node after sorting a part of linked list so that it's next
node can be assigned after sorting the succeeding list. temp is used to
store the next start1 because after sorting, the last node will be
different. So it is necessary to store the address of start1 before
sorting. We select the start1, end1, start2, end2 for sorting.
start1 - end1 may be considered as a list and start2 - end2 may be
considered as another list and we are merging these two sorted list in
merge function and assigning the starting address to the previous end
address."""
# Reject empty lists.
if not head:
return
gap = 1
length = list_length(head.start)
left = LinkedList()
right = LinkedList()
while gap < length:
left.start = head.start
while left.start:
# If this is first iteration
isFirstIter = False
if left.start = = head.start:
isFirstIter = True
# First part for merging
counter = gap
left.end = left.start
counter - = 1
while counter ! = 0 and left.end. next :
counter - = 1
left.end = left.end. next
# Second part for merging
right.start = left.end. next
if not right.start:
break
counter = gap
right.end = right.start
counter - = 1
while counter ! = 0 and right.end. next :
counter - = 1
right.end = right.end. next
# To store for next iteration.
temp = right.end. next
# Merging two parts.
merge(left, right)
# Update head for first iteration, else append after previous list.
if isFirstIter:
head.start = left.start
else :
prevend. next = left.start
prevend = right.end
left.start = temp
gap = gap * 2
prevend. next = left.start
def prints(head):
"""Print the linked list."""
if not head:
return
temp = head
while temp:
print (temp.data, end = ' ' )
temp = temp. next print ()
def push(head: LinkedList, data: int ) - > None :
"""Given a reference (pointer to pointer) to the head of a list and an
int, push a new node on the front of the list."""
new_node = Node(data)
new_node. next = head.start
head.start = new_node
# Driver code if __name__ = = '__main__' :
# start with empty list
head = LinkedList()
# create linked list
# 1.2.3.4.5.6.7
push(head, 6 )
push(head, 7 )
push(head, 2 )
push(head, 1 )
push(head, 3 )
push(head, 5 )
push(head, 4 )
mergeSort(head)
prints(head.start)
# This code is contributed by har2 (har-at-usf) |
// Iterative C# program to do merge sort on // linked list using System;
class GFG
{ /* Structure of the Node */ public class Node
{ public int data;
public Node next;
}; /* Function to calculate length of linked list */ static int length(Node current)
{ int count = 0;
while (current != null )
{
current = current.next;
count++;
}
return count;
} /* Merge function of Merge Sort to Merge the two sorted parts of the Linked List. We compare the next value of start1 and current value of start2 and insert start2 after start1 if it's smaller than next value of start1. We do this until start1 or start2 end. If start1 ends, then we assign next of start1 to start2 because start2 may have some elements left out which are greater than the last value of start1. If start2 ends then we assign end2 to end1. This is necessary because we use end2 in another function (mergeSort function) to determine the next start1 (i.e) start1 for next iteration = end2.next */ static Node merge(Node start1, Node end1,
Node start2, Node end2)
{ // Making sure that first node of second
// list is higher.
Node temp = null ;
if ((start1).data > (start2).data)
{
Node t = start1;
start1 = start2;
start2 = t;
t = end1;
end1 = end2;
end2 = t;
}
// Merging remaining nodes
Node astart = start1, aend = end1;
Node bstart = start2, bend = end2;
Node bendnext = (end2).next;
while (astart != aend && bstart != bendnext)
{
if (astart.next.data > bstart.data)
{
temp = bstart.next;
bstart.next = astart.next;
astart.next = bstart;
bstart = temp;
}
astart = astart.next;
}
if (astart == aend)
astart.next = bstart;
else
end2 = end1;
return start1;
} /* MergeSort of Linked List The gap is initially 1. It is incremented as 2, 4, 8, .. until it reaches the length of the linked list. For each gap, the linked list is sorted around the gap. The prevend stores the address of the last node after sorting a part of linked list so that it's next node can be assigned after sorting the succeeding list. temp is used to store the next start1 because after sorting, the last node will be different. So it is necessary to store the address of start1 before sorting. We select the start1, end1, start2, end2 for sorting. start1 - end1 may be considered as a list and start2 - end2 may be considered as another list and we are merging these two sorted list in merge function and assigning the starting address to the previous end address. */ static Node mergeSort(Node head)
{ if (head == null )
return head;
Node start1 = null , end1 = null ;
Node start2 = null , end2 = null ;
Node prevend = null ;
int len = length(head);
for ( int gap = 1; gap < len; gap = gap*2)
{
start1 = head;
while (start1 != null )
{
// If this is first iteration
Boolean isFirstIter = false ;
if (start1 == head)
isFirstIter = true ;
// First part for merging
int counter = gap;
end1 = start1;
while (--counter > 0 && end1.next != null )
end1 = end1.next;
// Second part for merging
start2 = end1.next;
if (start2 == null )
break ;
counter = gap;
end2 = start2;
while (--counter > 0 && end2.next != null )
end2 = end2.next;
// To store for next iteration.
Node temp = end2.next;
// Merging two parts.
merge(start1, end1, start2, end2);
// Update head for first iteration, else
// append after previous list
if (isFirstIter)
head = start1;
else
prevend.next = start1;
prevend = end2;
start1 = temp;
}
prevend.next = start1;
}
return head;
} /* Function to print the Linked List */ static void print(Node head)
{ if ((head) == null )
return ;
Node temp = head;
while (temp != null )
{
Console.Write( temp.data + " " );
temp = temp.next;
}
Console.Write( "\n" );
} /* Given a reference (pointer to pointer) to the head of a list and an int, push a new node on the front of the list. */ static Node push( Node head_ref,
int new_data)
{ Node new_node = new Node();
new_node.data = new_data;
new_node.next = (head_ref);
(head_ref) = new_node;
return head_ref;
} // Driver code public static void Main(String []args)
{ // start with empty list
Node head = null ;
// create linked list
// 1.2.3.4.5.6.7
head = push(head, 7);
head = push(head, 6);
head = push(head, 5);
head = push(head, 4);
head = push(head, 3);
head = push(head, 2);
head = push(head, 1);
head = mergeSort(head);
print(head);
} } // This code is contributed by Arnab Kundu |
<script> // Iterative JavaScript program to do merge sort on
// linked list
/* Structure of the Node */
class Node {
constructor() {
this .data = 0;
this .next = null ;
}
}
/* Function to calculate length of linked list */
function length(current) {
var count = 0;
while (current != null ) {
current = current.next;
count++;
}
return count;
}
/* Merge function of Merge Sort to Merge the two sorted parts
of the Linked List. We compare the next value of start1 and current value of start2 and insert start2 after start1 if it's smaller than next value of start1. We do this until start1 or start2 end. If start1 ends, then we assign next of start1 to start2 because start2 may have some elements left out which are greater than the last value of start1. If start2 ends then we assign end2 to end1. This is necessary because we use end2 in another function (mergeSort function) to determine the next start1 (i.e) start1 for next iteration = end2.next */ function merge(start1, end1, start2, end2) {
// Making sure that first node of second
// list is higher.
var temp = null ;
if (start1.data > start2.data) {
var t = start1;
start1 = start2;
start2 = t;
t = end1;
end1 = end2;
end2 = t;
}
// Merging remaining nodes
var astart = start1,
aend = end1;
var bstart = start2,
bend = end2;
var bendnext = end2.next;
while (astart != aend && bstart != bendnext) {
if (astart.next.data > bstart.data) {
temp = bstart.next;
bstart.next = astart.next;
astart.next = bstart;
bstart = temp;
}
astart = astart.next;
}
if (astart == aend) astart.next = bstart;
else end2 = end1;
return start1;
}
/* MergeSort of Linked List
The gap is initially 1. It is incremented as 2, 4, 8, .. until it reaches the length of the linked list. For each gap, the linked list is sorted around the gap. The prevend stores the address of the last node after sorting a part of linked list so that it's next node can be assigned after sorting the succeeding list. temp is used to store the next start1 because after sorting, the last node will be different. So it is necessary to store the address of start1 before sorting. We select the start1, end1, start2, end2 for sorting. start1 - end1 may be considered as a list and start2 - end2 may be considered as another list and we are merging these two sorted list in merge function and assigning the starting address to the previous end address. */ function mergeSort(head) {
if (head == null ) return head;
var start1 = null ,
end1 = null ;
var start2 = null ,
end2 = null ;
var prevend = null ;
var len = length(head);
for ( var gap = 1; gap < len; gap = gap * 2) {
start1 = head;
while (start1 != null ) {
// If this is first iteration
var isFirstIter = false ;
if (start1 == head) isFirstIter = true ;
// First part for merging
var counter = gap;
end1 = start1;
while (--counter > 0 && end1.next != null )
end1 = end1.next;
// Second part for merging
start2 = end1.next;
if (start2 == null ) break ;
counter = gap;
end2 = start2;
while (--counter > 0 && end2.next != null )
end2 = end2.next;
// To store for next iteration.
var temp = end2.next;
// Merging two parts.
merge(start1, end1, start2, end2);
// Update head for first iteration, else
// append after previous list
if (isFirstIter) head = start1;
else prevend.next = start1;
prevend = end2;
start1 = temp;
}
prevend.next = start1;
}
return head;
}
/* Function to print the Linked List */
function print(head) {
if (head == null ) return ;
var temp = head;
while (temp != null ) {
document.write(temp.data + " " );
temp = temp.next;
}
document.write( "<br>" );
}
/* Given a reference (pointer to
pointer) to the head of a list and an int, push a new node on the front of the list. */ function push(head_ref, new_data) {
var new_node = new Node();
new_node.data = new_data;
new_node.next = head_ref;
head_ref = new_node;
return head_ref;
}
// Driver code
// start with empty list
var head = null ;
// create linked list
// 1.2.3.4.5.6.7
head = push(head, 7);
head = push(head, 6);
head = push(head, 5);
head = push(head, 4);
head = push(head, 3);
head = push(head, 2);
head = push(head, 1);
head = mergeSort(head);
print(head);
</script> |
1 2 3 4 5 6 7
Complexity Analysis:
- Time Complexity : O(n Log n)
- Auxiliary Space : O(1)