📌  相关文章
📜  两个排序链表的交集

📅  最后修改于: 2021-04-27 20:52:07             🧑  作者: Mango

给定两个以递增顺序排序的列表,请创建并返回一个新列表,该列表代表两个列表的交集。新列表应使用自己的内存制作-原始列表不应更改。
例子:

Input: 
First linked list: 1->2->3->4->6
Second linked list be 2->4->6->8, 
Output: 2->4->6.
The elements 2, 4, 6 are common in 
both the list so they appear in the 
intersection list. 

Input: 
First linked list: 1->2->3->4->5
Second linked list be 2->3->4, 
Output: 2->3->4
The elements 2, 3, 4 are common in 
both the list so they appear in the 
intersection list.

方法1使用虚拟节点。
方法:
这个想法是在结果列表的开始使用一个临时的虚拟节点。指针尾部始终指向结果列表中的最后一个节点,因此可以轻松添加新节点。虚拟节点最初为尾部提供指向的存储空间。该虚拟节点是有效的,因为它只是临时的,并且在堆栈中分配。循环继续进行,从“ a”或“ b”中删除一个节点并将其添加到尾部。当遍历给定列表时,结果在dummy.next中,因为值是从哑元的下一个节点分配的。如果两个元素相等,则将其都移除,然后将元素插入尾部。否则,删除两个列表中较小的元素。

下面是上述方法的实现:

C++
#include
using namespace std;
 
/* Link list node */
struct Node {
    int data;
    Node* next;
};
 
void push(Node** head_ref, int new_data);
 
/*This solution uses the temporary
 dummy to build up the result list */
Node* sortedIntersect(Node* a, Node* b)
{
    Node dummy;
    Node* tail = &dummy;
    dummy.next = NULL;
 
    /* Once one or the other
    list runs out -- we're done */
    while (a != NULL && b != NULL) {
        if (a->data == b->data) {
            push((&tail->next), a->data);
            tail = tail->next;
            a = a->next;
            b = b->next;
        }
        /* advance the smaller list */
        else if (a->data < b->data)
            a = a->next;
        else
            b = b->next;
    }
    return (dummy.next);
}
 
/* UTILITY FUNCTIONS */
/* Function to insert a node at
the beginning of the linked list */
void push(Node** head_ref, int new_data)
{
    /* allocate node */
    Node* new_node = (Node*)malloc(
        sizeof(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 print nodes in
   a given linked list */
void printList(Node* node)
{
    while (node != NULL) {
        cout << node->data <<" ";
        node = node->next;
    }
}
 
/* Driver program to test above functions*/
int main()
{
    /* Start with the empty lists */
    Node* a = NULL;
    Node* b = NULL;
    Node* intersect = NULL;
 
    /* Let us create the first sorted
     linked list to test the functions
     Created linked list will be
     1->2->3->4->5->6 */
    push(&a, 6);
    push(&a, 5);
    push(&a, 4);
    push(&a, 3);
    push(&a, 2);
    push(&a, 1);
 
    /* Let us create the second sorted linked list
   Created linked list will be 2->4->6->8 */
    push(&b, 8);
    push(&b, 6);
    push(&b, 4);
    push(&b, 2);
 
    /* Find the intersection two linked lists */
    intersect = sortedIntersect(a, b);
 
    cout<<"Linked list containing common items of a & b \n";
    printList(intersect);
}


C
#include 
#include 
 
/* Link list node */
struct Node {
    int data;
    struct Node* next;
};
 
void push(struct Node** head_ref, int new_data);
 
/*This solution uses the temporary
 dummy to build up the result list */
struct Node* sortedIntersect(
    struct Node* a,
    struct Node* b)
{
    struct Node dummy;
    struct Node* tail = &dummy;
    dummy.next = NULL;
 
    /* Once one or the other
    list runs out -- we're done */
    while (a != NULL && b != NULL) {
        if (a->data == b->data) {
            push((&tail->next), a->data);
            tail = tail->next;
            a = a->next;
            b = b->next;
        }
        /* advance the smaller list */
        else if (a->data < b->data)
            a = a->next;
        else
            b = b->next;
    }
    return (dummy.next);
}
 
/* UTILITY FUNCTIONS */
/* Function to insert a node at
the beginning of the linked 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 print nodes in
   a given linked list */
void printList(struct Node* node)
{
    while (node != NULL) {
        printf("%d ", node->data);
        node = node->next;
    }
}
 
/* Driver program to test above functions*/
int main()
{
    /* Start with the empty lists */
    struct Node* a = NULL;
    struct Node* b = NULL;
    struct Node* intersect = NULL;
 
    /* Let us create the first sorted
     linked list to test the functions
     Created linked list will be
     1->2->3->4->5->6 */
    push(&a, 6);
    push(&a, 5);
    push(&a, 4);
    push(&a, 3);
    push(&a, 2);
    push(&a, 1);
 
    /* Let us create the second sorted linked list
   Created linked list will be 2->4->6->8 */
    push(&b, 8);
    push(&b, 6);
    push(&b, 4);
    push(&b, 2);
 
    /* Find the intersection two linked lists */
    intersect = sortedIntersect(a, b);
 
    printf("\n Linked list containing common items of a & b \n ");
    printList(intersect);
 
    getchar();
}


Java
class GFG
{
   
    // head nodes for pointing to 1st and 2nd linked lists
    static Node a = null, b = null;
   
    // dummy node for storing intersection
    static Node dummy = null;
   
    // tail node for keeping track of
  // last node so that it makes easy for insertion
    static Node tail = null;
     
    // class - Node
    static class Node {
        int data;
        Node next;
 
        Node(int data) {
            this.data = data;
            next = null;
        }
    }
     
    // function for printing the list
    void printList(Node start) {
        Node p = start;
        while (p != null) {
            System.out.print(p.data + " ");
            p = p.next;
        }
        System.out.println();
    }
     
    // inserting elements into list
    void push(int data) {
        Node temp = new Node(data);
        if(dummy == null) {
            dummy = temp;
            tail = temp;
        }
        else {
            tail.next = temp;
            tail = temp;
        }
    }
     
    // function for finding intersection and adding it to dummy list
    void sortedIntersect()
    {
       
        // pointers for iterating
        Node p = a,q = b;
        while(p != null  &&  q != null)
        {
            if(p.data == q.data)
            {
                // add to dummy list
                push(p.data);
                p = p.next;
                q = q.next;
            }
            else if(p.data < q.data)
                p = p.next;
            else
                q= q.next;
        }
    }
     
  // Driver code
    public static void main(String args[])
    {
        GFG list = new GFG();
         
        // creating first linked list
        list.a = new Node(1);
        list.a.next = new Node(2);
        list.a.next.next = new Node(3);
        list.a.next.next.next = new Node(4);
        list.a.next.next.next.next = new Node(6);
 
        // creating second linked list
        list.b = new Node(2);
        list.b.next = new Node(4);
        list.b.next.next = new Node(6);
        list.b.next.next.next = new Node(8);
         
        // function call for intersection
        list.sortedIntersect();
       
        // print required intersection
        System.out.println("Linked list containing common items of a & b");
        list.printList(dummy);
    }
}
 
// This code is contributed by Likhita AVL


Python3
''' Link list node '''
class Node:
    def __init__(self):  
        self.data = 0
        self.next = None
     
'''This solution uses the temporary
 dummy to build up the result list '''
def sortedIntersect(a, b):
    dummy = Node()
    tail = dummy;
    dummy.next = None;
  
    ''' Once one or the other
    list runs out -- we're done '''
    while (a != None and b != None):
        if (a.data == b.data):
            tail.next = push((tail.next), a.data);
            tail = tail.next;
            a = a.next;
            b = b.next;
         
        # advance the smaller list
        elif(a.data < b.data):
            a = a.next;
        else:
            b = b.next;   
    return (dummy.next);
 
''' UTILITY FUNCTIONS '''
''' Function to insert a node at
the beginning of the linked 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 print nodes in
   a given linked list '''
def printList(node):
    while (node != None):
        print(node.data, end=' ')
        node = node.next;
      
''' Driver code'''
if __name__=='__main__':
     
    ''' Start with the empty lists '''
    a = None;
    b = None;
    intersect = None;
  
    ''' Let us create the first sorted
     linked list to test the functions
     Created linked list will be
     1.2.3.4.5.6 '''
    a = push(a, 6);
    a = push(a, 5);
    a = push(a, 4);
    a = push(a, 3);
    a = push(a, 2);
    a = push(a, 1);
  
    ''' Let us create the second sorted linked list
   Created linked list will be 2.4.6.8 '''
    b = push(b, 8);
    b = push(b, 6);
    b = push(b, 4);
    b = push(b, 2);
  
    ''' Find the intersection two linked lists '''
    intersect = sortedIntersect(a, b);
  
    print("Linked list containing common items of a & b ");
    printList(intersect);
 
# This code is contributed by rutvik_56.


C
#include 
#include 
 
/* Link list node */
struct Node {
    int data;
    struct Node* next;
};
 
void push(struct Node** head_ref,
          int new_data);
 
/* This solution uses the local reference */
struct Node* sortedIntersect(
    struct Node* a,
    struct Node* b)
{
    struct Node* result = NULL;
    struct Node** lastPtrRef = &result;
 
    /* Advance comparing the first
     nodes in both lists.
    When one or the other list runs
     out, we're done. */
    while (a != NULL && b != NULL) {
        if (a->data == b->data) {
            /* found a node for the intersection */
            push(lastPtrRef, a->data);
            lastPtrRef = &((*lastPtrRef)->next);
            a = a->next;
            b = b->next;
        }
        else if (a->data < b->data)
            a = a->next; /* advance the smaller list */
        else
            b = b->next;
    }
    return (result);
}
 
/* UTILITY FUNCTIONS */
/* Function to insert a node at the
   beginging of the linked 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 print nodes in a given linked list */
void printList(struct Node* node)
{
    while (node != NULL) {
        printf("%d ", node->data);
        node = node->next;
    }
}
 
/* Driver program to test above functions*/
int main()
{
    /* Start with the empty lists */
    struct Node* a = NULL;
    struct Node* b = NULL;
    struct Node* intersect = NULL;
 
    /* Let us create the first sorted
     linked list to test the functions
   Created linked list will be
   1->2->3->4->5->6 */
    push(&a, 6);
    push(&a, 5);
    push(&a, 4);
    push(&a, 3);
    push(&a, 2);
    push(&a, 1);
 
    /* Let us create the second sorted linked list
   Created linked list will be 2->4->6->8 */
    push(&b, 8);
    push(&b, 6);
    push(&b, 4);
    push(&b, 2);
 
    /* Find the intersection two linked lists */
    intersect = sortedIntersect(a, b);
 
    printf("\n Linked list containing common items of a & b \n ");
    printList(intersect);
 
    getchar();
}


C
#include 
#include 
 
/* Link list node */
struct Node {
    int data;
    struct Node* next;
};
 
struct Node* sortedIntersect(
    struct Node* a,
    struct Node* b)
{
    /* base case */
    if (a == NULL || b == NULL)
        return NULL;
 
    /* If both lists are non-empty */
 
    /* advance the smaller list and call recursively */
    if (a->data < b->data)
        return sortedIntersect(a->next, b);
 
    if (a->data > b->data)
        return sortedIntersect(a, b->next);
 
    // Below lines are executed only
    // when a->data == b->data
    struct Node* temp
        = (struct Node*)malloc(
            sizeof(struct Node));
    temp->data = a->data;
 
    /* advance both lists and call recursively */
    temp->next = sortedIntersect(a->next, b->next);
    return temp;
}
 
/* UTILITY FUNCTIONS */
/* Function to insert a node at
the beginging of the linked 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 print nodes in a given linked list */
void printList(struct Node* node)
{
    while (node != NULL) {
        printf("%d ", node->data);
        node = node->next;
    }
}
 
/* Driver program to test above functions*/
int main()
{
    /* Start with the empty lists */
    struct Node* a = NULL;
    struct Node* b = NULL;
    struct Node* intersect = NULL;
 
    /* Let us create the first sorted
      linked list to test the functions
     Created linked list will be
      1->2->3->4->5->6 */
    push(&a, 6);
    push(&a, 5);
    push(&a, 4);
    push(&a, 3);
    push(&a, 2);
    push(&a, 1);
 
    /* Let us create the second sorted linked list
     Created linked list will be 2->4->6->8 */
    push(&b, 8);
    push(&b, 6);
    push(&b, 4);
    push(&b, 2);
 
    /* Find the intersection two linked lists */
    intersect = sortedIntersect(a, b);
 
    printf("\n Linked list containing common items of a & b \n ");
    printList(intersect);
 
    return 0;
}


输出:

Linked list containing common items of a & b 
 2 4 6

复杂度分析:

  • 时间复杂度: O(m + n),其中m和n分别是第一链表和第二链表中的节点数。
    仅需要遍历列表之一。
  • 辅助空间: O(min(m,n))。
    输出列表最多可以存储min(m,n)个节点。

方法2使用本地引用。
方法:此解决方案在结构上与上述解决方案非常相似,但避免使用虚拟节点,而是维护一个结构节点**指针lastPtrRef,该指针始终指向结果列表的最后一个指针。这解决了虚拟节点所做的相同情况—在结果列表为空时处理结果列表。如果列表建立在其尾部,则可以使用虚拟节点或结构节点**“引用”策略。

下面是上述方法的实现:

C

#include 
#include 
 
/* Link list node */
struct Node {
    int data;
    struct Node* next;
};
 
void push(struct Node** head_ref,
          int new_data);
 
/* This solution uses the local reference */
struct Node* sortedIntersect(
    struct Node* a,
    struct Node* b)
{
    struct Node* result = NULL;
    struct Node** lastPtrRef = &result;
 
    /* Advance comparing the first
     nodes in both lists.
    When one or the other list runs
     out, we're done. */
    while (a != NULL && b != NULL) {
        if (a->data == b->data) {
            /* found a node for the intersection */
            push(lastPtrRef, a->data);
            lastPtrRef = &((*lastPtrRef)->next);
            a = a->next;
            b = b->next;
        }
        else if (a->data < b->data)
            a = a->next; /* advance the smaller list */
        else
            b = b->next;
    }
    return (result);
}
 
/* UTILITY FUNCTIONS */
/* Function to insert a node at the
   beginging of the linked 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 print nodes in a given linked list */
void printList(struct Node* node)
{
    while (node != NULL) {
        printf("%d ", node->data);
        node = node->next;
    }
}
 
/* Driver program to test above functions*/
int main()
{
    /* Start with the empty lists */
    struct Node* a = NULL;
    struct Node* b = NULL;
    struct Node* intersect = NULL;
 
    /* Let us create the first sorted
     linked list to test the functions
   Created linked list will be
   1->2->3->4->5->6 */
    push(&a, 6);
    push(&a, 5);
    push(&a, 4);
    push(&a, 3);
    push(&a, 2);
    push(&a, 1);
 
    /* Let us create the second sorted linked list
   Created linked list will be 2->4->6->8 */
    push(&b, 8);
    push(&b, 6);
    push(&b, 4);
    push(&b, 2);
 
    /* Find the intersection two linked lists */
    intersect = sortedIntersect(a, b);
 
    printf("\n Linked list containing common items of a & b \n ");
    printList(intersect);
 
    getchar();
}

输出:

Linked list containing common items of a & b 
 2 4 6

复杂度分析:

  • 时间复杂度: O(m + n),其中m和n分别是第一链表和第二链表中的节点数。
    仅需要遍历列表之一。
  • 辅助空间: O(max(m,n))。
    输出列表最多可以存储m + n个节点。

方法3递归解决方案。
方法:
递归方法与以上两种方法非常相似。构建一个包含两个节点并返回链接列表节点的递归函数。比较两个列表的第一个元素。

  • 如果它们相似,则用两个列表的下一个节点调用递归函数。使用当前节点的数据创建一个节点,并将从递归函数返回的节点放入所创建节点的下一个指针。返回创建的节点。
  • 如果值不相等,则删除两个列表中的较小节点,然后调用递归函数。

下面是上述方法的实现:

C

#include 
#include 
 
/* Link list node */
struct Node {
    int data;
    struct Node* next;
};
 
struct Node* sortedIntersect(
    struct Node* a,
    struct Node* b)
{
    /* base case */
    if (a == NULL || b == NULL)
        return NULL;
 
    /* If both lists are non-empty */
 
    /* advance the smaller list and call recursively */
    if (a->data < b->data)
        return sortedIntersect(a->next, b);
 
    if (a->data > b->data)
        return sortedIntersect(a, b->next);
 
    // Below lines are executed only
    // when a->data == b->data
    struct Node* temp
        = (struct Node*)malloc(
            sizeof(struct Node));
    temp->data = a->data;
 
    /* advance both lists and call recursively */
    temp->next = sortedIntersect(a->next, b->next);
    return temp;
}
 
/* UTILITY FUNCTIONS */
/* Function to insert a node at
the beginging of the linked 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 print nodes in a given linked list */
void printList(struct Node* node)
{
    while (node != NULL) {
        printf("%d ", node->data);
        node = node->next;
    }
}
 
/* Driver program to test above functions*/
int main()
{
    /* Start with the empty lists */
    struct Node* a = NULL;
    struct Node* b = NULL;
    struct Node* intersect = NULL;
 
    /* Let us create the first sorted
      linked list to test the functions
     Created linked list will be
      1->2->3->4->5->6 */
    push(&a, 6);
    push(&a, 5);
    push(&a, 4);
    push(&a, 3);
    push(&a, 2);
    push(&a, 1);
 
    /* Let us create the second sorted linked list
     Created linked list will be 2->4->6->8 */
    push(&b, 8);
    push(&b, 6);
    push(&b, 4);
    push(&b, 2);
 
    /* Find the intersection two linked lists */
    intersect = sortedIntersect(a, b);
 
    printf("\n Linked list containing common items of a & b \n ");
    printList(intersect);
 
    return 0;
}

输出:

Linked list containing common items of a & b 
 2 4 6

复杂度分析:

  • 时间复杂度: O(m + n),其中m和n分别是第一链表和第二链表中的节点数。
    仅需要遍历列表之一。
  • 辅助空间: O(max(m,n))。
    输出列表最多可以存储m + n个节点。