📜  链表的迭代归并排序

📅  最后修改于: 2022-05-13 01:57:45.605000             🧑  作者: Mango

链表的迭代归并排序

给定一个整数单链表,任务是使用迭代归并排序对其进行排序。

合并排序通常用于对链表进行排序。在这里讨论。但是,上面讨论的方法使用 Stack 来存储递归调用。如果要排序的链表太大,这可能会消耗大量内存。因此,本文讨论了一种纯迭代的归并排序方法,没有递归调用。
我们在这篇文章中使用了自下而上的归并排序方法。我们知道合并排序首先合并两个项目,然后是 4 个项目,依此类推。这个想法是使用一个整数变量来存储间隙,以找到需要对链表进行排序的中点。因此,问题简化为合并这里讨论的两个排序的链表。但是,我们不使用附加列表来保留合并列表。相反,我们合并列表本身。间隙在每次迭代中以指数方式增加 2,并重复该过程。

C++
// Iterative C++ program to do merge sort on
// linked list
#include 
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
  
''' Structure of the Node '''
class Node:  
    def __init__(self, data):      
        self.data = data
        self.next = None
  
''' Function to calculate length of linked list '''
def length(current):
    count = 0;
    while (current != None):
        current = current.next;
        count += 1
 
    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 '''
def merge(start1, end1, start2, end2):
  
    # Making sure that first node of second
    # list is higher.
    temp = None;
    if ((start1).data > (start2).data):
        start1, start2 = start2, start1
        end1,end2 = end2, end1
  
    # Merging remaining nodes
    astart = start1
    aend = end1;
    bstart = start2
    bend = end2;
    bendnext = (end2).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:
        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. '''
def mergeSort(head):
    if (head == None):
        return;
    start1 = None
    end1 = None;
    start2 = None
    end2 = None;
    prevend = None;  
    len = length(head);   
    gap = 1   
    while gap < len:      
        start1 = head;
        while (start1):
  
            # If this is first iteration
            isFirstIter = 0;
            if (start1 == head):
                isFirstIter = 1;
  
            # First part for merging
            counter = gap;
            end1 = start1;
            while (counter != 0 and end1.next):
                counter -= 1
                end1 = end1.next;
  
            # Second part for merging
            start2 = end1.next;
            if (not start2):
                break;
            counter = gap;
            end2 = start2;
            while (counter != 0 and end2.next):
                counter -= 1
                end2 = end2.next;
  
            # To store for next iteration.
            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;
            gap = gap*2      
        prevend.next = start1;
     
''' Function to print the Linked List '''
def prints(head):
    if ((head) == None):
        return;
    temp = head;
    while (temp != None):
        print(temp.data, end=' ')
        temp = temp.next;   
    print()    
  
''' 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. '''
def push(head_ref,  new_data):
    new_node = Node(new_data)
    new_node.next = (head_ref);
    (head_ref) = new_node;
    return head_ref
 
# Driver code
if __name__=='__main__':
     
    # start with empty list
    head = None;
    
    # 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);
    mergeSort(head);
    prints(head);
 
# This code is contributed by rutvik_56


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


输出:

1 2 3 4 5 6 7

时间复杂度: O(n Log n)
辅助空间: O(1)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程