Open In App

Iterative Merge Sort for Linked List

Improve
Improve
Like Article
Like
Save
Share
Report

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:

C++




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


Java




// 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


Python3




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


C#




// 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


Javascript




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


Output

1 2 3 4 5 6 7 

Complexity Analysis:

  • Time Complexity : O(n Log n) 
  • Auxiliary Space : O(1) 


Last Updated : 01 Sep, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads