📜  就地合并两个链表而不改变第一个链表的链接

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

就地合并两个链表而不改变第一个链表的链接

给定两个分别具有 n 和 m 个元素的已排序单链表,使用常量空间合并它们。两个列表中的前 n 个最小元素应成为第一个列表的一部分,其余元素应成为第二个列表的一部分。应保持排序顺序。我们不允许更改第一个链表的指针。

例如,

Input:
First List: 2->4->7->8->10
Second List: 1->3->12

Output: 
First List: 1->2->3->4->7
Second List: 8->10->12

我们强烈建议您将浏览器最小化,然后自己先尝试一下。
如果我们允许改变第一个链表的指针,问题就变得很简单了。如果我们被允许更改链接,我们可以简单地做一些类似归并排序算法合并的事情。我们将前 n 个最小元素分配给第一个链表,其中 n 是第一个链表中元素的数量,其余的分配给第二个链表。我们可以在 O(m + n) 时间和 O(1) 空间内实现这一点,但是这个解决方案违反了我们不能更改第一个列表的链接的要求。

这个问题变得有点棘手,因为我们不允许更改第一个链表中的指针。这个想法类似于这篇文章,但是由于我们给出了单向链表,我们无法向后处理 LL2 的最后一个元素。

这个想法是对于 LL1 的每个元素,我们将它与 LL2 的第一个元素进行比较。如果 LL1 的元素大于 LL2 的第一个元素,那么我们交换所涉及的两个元素。为了保持 LL2 排序,我们需要将 LL2 的第一个元素放在正确的位置。我们可以通过遍历 LL2 一次并纠正指针来发现不匹配。



下面是这个想法的实现。

C++
// C++ Program to merge two sorted linked lists without
// using any extra space and without changing links
// of first list
#include 
using namespace std;
 
 /* Structure for a linked list node */
struct Node
{
    int data;
    struct Node *next;
};
 
/* 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)
{
    /* allocate node */
    struct Node* new_node =
        (struct Node*) malloc(sizeof(struct Node));
 
    /* put in the data  */
    new_node->data  = new_data;
 
    /* link the old list off the new node */
    new_node->next = (*head_ref);
 
    /* move the head to point to the new node */
    (*head_ref)    = new_node;
}
 
// Function to merge two sorted linked lists
// LL1 and LL2 without using any extra space.
void mergeLists(struct Node *a, struct Node * &b)
{
    // run till either one of a or b runs out
    while (a && b)
    {
        // for each element of LL1,
        // compare it with first element of LL2.
        if (a->data > b->data)
        {
            // swap the two elements involved
            // if LL1 has a greater element
            swap(a->data, b->data);
 
            struct Node *temp = b;
 
            // To keep LL2 sorted, place first
            // element of LL2 at its correct place
            if (b->next && b->data > b->next->data)
            {
                b = b->next;
                struct Node *ptr= b, *prev = NULL;
 
                // find mismatch by traversing the
                // second linked list once
                while (ptr && ptr->data < temp->data)
                {
                    prev = ptr;
                    ptr = ptr -> next;
                }
 
                // correct the pointers
                prev->next = temp;
                temp->next = ptr;
            }
        }
 
        // move LL1 pointer to next element
        a = a->next;
    }
}
 
// Code to print the linked link
void printList(struct Node *head)
{
    while (head)
    {
        cout << head->data << "->" ;
        head = head->next;
    }
    cout << "NULL" << endl;
}
 
// Driver code
int main()
{
    struct Node *a = NULL;
    push(&a, 10);
    push(&a, 8);
    push(&a, 7);
    push(&a, 4);
    push(&a, 2);
 
    struct Node *b = NULL;
    push(&b, 12);
    push(&b, 3);
    push(&b, 1);
 
    mergeLists(a, b);
 
    cout << "First List: ";
    printList(a);
 
    cout << "Second List: ";
    printList(b);
 
    return 0;
}


Python3
# Python3 program to merge two sorted linked
# lists without using any extra space and
# without changing links of first list
 
# Structure for a linked list node
class Node:
     
    def __init__(self):
         
        self.data = 0
        self.next = 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.
def push(head_ref, new_data):
 
    # Allocate node
    new_node = Node()
  
    # Put in the data 
    new_node.data  = new_data
  
    # Link the old list off the new node
    new_node.next = (head_ref)
  
    # Move the head to point to the new node
    (head_ref) = new_node
    return head_ref
 
# Function to merge two sorted linked lists
# LL1 and LL2 without using any extra space.
def mergeLists(a, b):
 
    # Run till either one of a
    # or b runs out
    while (a and b):
 
        # For each element of LL1, compare
        # it with first element of LL2.
        if (a.data > b.data):
     
            # Swap the two elements involved
            # if LL1 has a greater element
            a.data, b.data = b.data, a.data
  
            temp = b
  
            # To keep LL2 sorted, place first
            # element of LL2 at its correct place
            if (b.next and b.data > b.next.data):
                b = b.next
                ptr = b
                prev = None
                 
                # Find mismatch by traversing the
                # second linked list once
                while (ptr and ptr.data < temp.data):
                    prev = ptr
                    ptr = ptr.next
         
                # Correct the pointers
                prev.next = temp
                temp.next = ptr
         
        # Move LL1 pointer to next element
        a = a.next
     
# Function to print the linked link
def printList(head):
 
    while (head):
        print(head.data, end = '->')
        head = head.next
     
    print('NULL')
     
# Driver code
if __name__=='__main__':
     
    a = None
    a = push(a, 10)
    a = push(a, 8)
    a = push(a, 7)
    a = push(a, 4)
    a = push(a, 2)
  
    b = None
    b = push(b, 12)
    b = push(b, 3)
    b = push(b, 1)
  
    mergeLists(a, b)
  
    print("First List: ", end = '')
    printList(a)
  
    print("Second List: ", end = '')
    printList(b)
 
# This code is contributed by rutvik_56


输出 :

First List: 1->2->3->4->7->NULL
Second List: 8->10->12->NULL

时间复杂度: O(mn)

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