Open In App

Union and Intersection of two Linked List using Merge Sort

Improve
Improve
Like Article
Like
Save
Share
Report

Given two Linked Lists, create union and intersection lists that contain the union and intersection of the elements present in the given lists. The order of elements in output lists doesn’t matter. 

Examples:

Input:
List1: 10 -> 15 -> 4 -> 20
List2: 8 -> 4 -> 2 -> 10
Output:
Intersection List: 4 -> 10
Union List: 2 -> 8 -> 20 -> 4 -> 15 -> 10
Explanation: In this two lists 4 and 10 nodes
are common. The union lists contains
all the nodes of both the lists.
Input:
List1: 1 -> 2 -> 3 -> 4
List2: 3 -> 4 -> 8 -> 10
Output:
Intersection List: 3 -> 4
Union List: 1 -> 2 -> 3 -> 4 -> 8 -> 10
Explanation: In this two lists 4 and 3 nodes
are common. The union lists contains
all the nodes of both the lists.

There were three methods discussed in this post with an implementation of Method 1. In this post, we will see an implementation of Method 2 i.e. Using Merge sort.

Implementation:
Following are the steps to be followed to get union and intersection lists.
1) Sort both Linked Lists using merge sort.
This step takes O(mLogm) time.
2) Linearly scan both sorted lists to get the union and intersection.
This step takes O(m + n) time.

Algorithm:

  1. Sort both Linked Lists using merge sort.
  2. Linearly scan both sorted lists to get the union and intersection.
  3. Perform merge like operation on both linked lists, Keep to a pointer which points initially to the first node of both lists.
  4. Compare both the nodes until and unless both the pointers are not null.
    1. if equal add it to the intersection list and union list and move to next node of both the pointers
    2. if not equal then insert the smaller pointer value into union list and move to the next node
  5. If one of the pointers is null then traverse the other list and all its nodes to union list.

Just like Method 1, this method also assumes that there are distinct elements in the lists. 

CPP




// C++ program to find union and intersection of
// two unsorted linked lists in O(n Log n) time.
#include <bits/stdc++.h>
using namespace std;
 
/* Link list node */
struct Node {
    int data;
    struct Node* next;
};
 
/* A utility function to insert a
node at the beginning of a 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 of the new node */
    new_node->next = (*head_ref);
 
    /* move the head to point to the new node */
    (*head_ref) = new_node;
}
 
/* UTILITY FUNCTIONS */
/* Split the nodes of the given
list into front and back halves,
and return the two lists
using the reference parameters.
If the length is odd, the
extra node should go in the
front list.
        Uses the fast/slow pointer strategy. */
void FrontBackSplit(struct Node* source,
                    struct Node** frontRef,
                    struct Node** backRef)
{
    struct Node* fast;
    struct Node* slow;
    if (source == NULL || source->next == NULL) {
        /* length < 2 cases */
        *frontRef = source;
        *backRef = NULL;
    }
    else {
        slow = source;
        fast = source->next;
 
        /* Advance 'fast' two nodes, and
        advance 'slow' one node */
        while (fast != NULL) {
            fast = fast->next;
            if (fast != NULL) {
                slow = slow->next;
                fast = fast->next;
            }
        }
 
        /* 'slow' is before the midpoint in the list,
                so split it in two at that point. */
        *frontRef = source;
        *backRef = slow->next;
        slow->next = NULL;
    }
}
 
 
struct Node* SortedMerge(struct Node* a, struct Node* b)
{
    struct Node* result = NULL;
 
    /* Base cases */
    if (a == NULL)
        return (b);
    else if (b == NULL)
        return (a);
 
    /* Pick either a or b, and recur */
    if (a->data <= b->data) {
        result = a;
        result->next = SortedMerge(a->next, b);
    }
    else {
        result = b;
        result->next = SortedMerge(a, b->next);
    }
    return (result);
}
 
/* sorts the linked list by changing
next pointers (not data) */
void mergeSort(struct Node** headRef)
{
    struct Node* head = *headRef;
    struct Node *a, *b;
 
    /* Base case -- length 0 or 1 */
    if ((head == NULL) || (head->next == NULL))
        return;
 
    /* Split head into 'a' and 'b' sublists */
    FrontBackSplit(head, &a, &b);
 
    /* Recursively sort the sublists */
    mergeSort(&a);
    mergeSort(&b);
 
    /* answer = merge the two sorted lists together */
    *headRef = SortedMerge(a, b);
}
 
/* Function to get union of two
linked lists head1 and head2 */
struct Node* getUnion(struct Node* head1,
                      struct Node* head2)
{
    struct Node* result = NULL;
    struct Node *t1 = head1, *t2 = head2;
 
    // Traverse both lists and store the
    // element in the resu1tant list
    while (t1 != NULL && t2 != NULL) {
        // Move to the next of first list
        // if its element is smaller
        if (t1->data < t2->data) {
            push(&result, t1->data);
            t1 = t1->next;
        }
 
        // Else move to the next of second list
        else if (t1->data > t2->data) {
            push(&result, t2->data);
            t2 = t2->next;
        }
 
        // If same then move to the next node
        // in both lists
        else {
            push(&result, t2->data);
            t1 = t1->next;
            t2 = t2->next;
        }
    }
 
    /* Print remaining elements of the lists */
    while (t1 != NULL) {
        push(&result, t1->data);
        t1 = t1->next;
    }
    while (t2 != NULL) {
        push(&result, t2->data);
        t2 = t2->next;
    }
 
    return result;
}
 
/* Function to get intersection of
two linked lists head1 and head2 */
struct Node* getIntersection(struct Node* head1,
                             struct Node* head2)
{
    struct Node* result = NULL;
    struct Node *t1 = head1, *t2 = head2;
 
    // Traverse both lists and store the same element
    // in the resu1tant list
    while (t1 != NULL && t2 != NULL) {
        // Move to the next of first
        // list if smaller
        if (t1->data < t2->data)
            t1 = t1->next;
 
        // Move to the next of second
        // list if it is smaller
        else if (t1->data > t2->data)
            t2 = t2->next;
 
        // If both are same
        else {
            // Store current element in the list
            push(&result, t2->data);
 
            // Move to the next node of both lists
            t1 = t1->next;
            t2 = t2->next;
        }
    }
 
    // return the resultant list
    return result;
}
 
/* A utility function to print a linked list*/
void printList(struct Node* node)
{
    while (node != NULL) {
        printf("%d ", node->data);
        node = node->next;
    }
}
 
/* Driver program to test above function*/
int main()
{
    /* Start with the empty list */
    struct Node* head1 = NULL;
    struct Node* head2 = NULL;
    struct Node* intersection_list = NULL;
    struct Node* union_list = NULL;
 
    /*create a linked list 11->10->15->4->20 */
    push(&head1, 20);
    push(&head1, 4);
    push(&head1, 15);
    push(&head1, 10);
    push(&head1, 11);
 
    /*create a linked list 8->4->2->10 */
    push(&head2, 10);
    push(&head2, 2);
    push(&head2, 4);
    push(&head2, 8);
 
    /* Sort the above created Linked List */
    mergeSort(&head1);
    mergeSort(&head2);
 
    intersection_list = getIntersection(head1, head2);
    union_list = getUnion(head1, head2);
 
    printf("First list is \n");
    printList(head1);
 
    printf("\nSecond list is \n");
    printList(head2);
 
    printf("\nIntersection list is \n");
    printList(intersection_list);
 
    printf("\nUnion list is \n");
    printList(union_list);
 
    return 0;
}


Java




import java.util.HashMap;
import java.util.HashSet;
 
/* Linked list Node*/
class Node {
    int data;
    Node next;
    Node(int d)
    {
        data = d;
        next = null;
    }
}
 
class LinkedList {
  //create head of list
    Node head;
 
    /* Utility function to print list */
    void printList()
    {
        Node temp = head;
        while (temp != null) {
            System.out.print(temp.data + " ");
            temp = temp.next;
        }
        System.out.println();
    }
 
    /* Inserts a node at start of linked list */
    void push(int new_data)
    {
        /* 1 & 2: Allocate the Node &
        Put in the data*/
        Node new_node = new Node(new_data);
 
        /* 3. Make next of new Node as head */
        new_node.next = head;
 
        /* 4. Move the head to point to new Node */
        head = new_node;
    }
 
    public void append(int new_data)
    {
        if (this.head == null) {
            Node n = new Node(new_data);
            this.head = n;
            return;
        }
        Node n1 = this.head;
        Node n2 = new Node(new_data);
        while (n1.next != null) {
            n1 = n1.next;
        }
 
        n1.next = n2;
        n2.next = null;
    }
 
    /* A utility function that returns true if data is
    present in linked list else return false */
    boolean isPresent(Node head, int data)
    {
        Node t = head;
        while (t != null) {
            if (t.data == data)
                return true;
            t = t.next;
        }
        return false;
    }
 
    LinkedList getIntersection(Node head1, Node head2)
    {
        HashSet<Integer> hset = new HashSet<>();
        Node n1 = head1;
        Node n2 = head2;
        LinkedList result = new LinkedList();
 
        // loop stores all the elements of list1 in hset
        while (n1 != null) {
            if (hset.contains(n1.data)) {
                hset.add(n1.data);
            }
            else {
                hset.add(n1.data);
            }
            n1 = n1.next;
        }
 
        // For every element of list2 present in hset
        // loop inserts the element into the result
        while (n2 != null) {
            if (hset.contains(n2.data)) {
                result.push(n2.data);
            }
            n2 = n2.next;
        }
        return result;
    }
 
    LinkedList getUnion(Node head1, Node head2)
    {
        // HashMap that will store the
        // elements of the lists with their counts
        HashMap<Integer, Integer> hmap = new HashMap<>();
        Node n1 = head1;
        Node n2 = head2;
        LinkedList result = new LinkedList();
 
        // loop inserts the elements and the count of
        // that element of list1 into the hmap
        while (n1 != null) {
            if (hmap.containsKey(n1.data)) {
                int val = hmap.get(n1.data);
                hmap.put(n1.data, val + 1);
            }
            else {
                hmap.put(n1.data, 1);
            }
            n1 = n1.next;
        }
 
        // loop further adds the elements of list2 with
        // their counts into the hmap
        while (n2 != null) {
            if (hmap.containsKey(n2.data)) {
                int val = hmap.get(n2.data);
                hmap.put(n2.data, val + 1);
            }
            else {
                hmap.put(n2.data, 1);
            }
            n2 = n2.next;
        }
 
        // Eventually add all the elements
        // into the result that are present in the hmap
        for (int a : hmap.keySet()) {
            result.append(a);
        }
        return result;
    }
 
    /* Driver program to test above functions */
    public static void main(String args[])
    {
        LinkedList llist1 = new LinkedList();
        LinkedList llist2 = new LinkedList();
        LinkedList union = new LinkedList();
        LinkedList intersection = new LinkedList();
 
        /*create a linked list 10->15->4->20 */
        llist1.push(20);
        llist1.push(4);
        llist1.push(15);
        llist1.push(10);
        llist1.push(11);
 
        /*create a linked list 8->4->2->10 */
        llist2.push(10);
        llist2.push(2);
        llist2.push(4);
        llist2.push(8);
 
        intersection = intersection.getIntersection(
            llist1.head, llist2.head);
        union = union.getUnion(llist1.head, llist2.head);
 
        System.out.println("\nFirst List is\n");
        llist1.printList();
 
        System.out.println("\nSecond List is\n");
        llist2.printList();
 
        System.out.println("\nIntersection List is\n");
        intersection.printList();
 
        System.out.println("\nUnion List is\n");
        union.printList();
    }
}
 
// This code is Contributed by Gaurav


C#




using System;
 
public class Node {
    public int data;
    public Node next;
}
 
public class Program {
    public static void Push(ref 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;
    }
 
    public static void FrontBackSplit(Node source,
                                      out Node frontRef,
                                      out Node backRef)
    {
        Node fast;
        Node slow;
        if (source == null || source.next == null) {
            frontRef = source;
            backRef = null;
        }
        else {
            slow = source;
            fast = source.next;
 
            while (fast != null) {
                fast = fast.next;
                if (fast != null) {
                    slow = slow.next;
                    fast = fast.next;
                }
            }
            frontRef = source;
            backRef = slow.next;
            slow.next = null;
        }
    }
 
    public static Node SortedMerge(Node a, Node b)
    {
        Node result = null;
 
        if (a == null)
            return b;
        else if (b == null)
            return a;
 
        if (a.data <= b.data) {
            result = a;
            result.next = SortedMerge(a.next, b);
        }
        else {
            result = b;
            result.next = SortedMerge(a, b.next);
        }
        return result;
    }
 
    public static void MergeSort(ref Node headRef)
    {
        Node head = headRef;
        Node a, b;
 
        if (head == null || head.next == null)
            return;
 
        FrontBackSplit(head, out a, out b);
 
        MergeSort(ref a);
        MergeSort(ref b);
 
        headRef = SortedMerge(a, b);
    }
 
    public static Node GetUnion(Node head1, Node head2)
    {
        Node result = null;
        Node t1 = head1, t2 = head2;
 
        while (t1 != null && t2 != null) {
            if (t1.data < t2.data) {
                Push(ref result, t1.data);
                t1 = t1.next;
            }
            else if (t1.data > t2.data) {
                Push(ref result, t2.data);
                t2 = t2.next;
            }
            else {
                Push(ref result, t2.data);
                t1 = t1.next;
                t2 = t2.next;
            }
        }
 
        while (t1 != null) {
            Push(ref result, t1.data);
            t1 = t1.next;
        }
        while (t2 != null) {
            Push(ref result, t2.data);
            t2 = t2.next;
        }
 
        return result;
    }
 
    public static Node GetIntersection(Node head1,
                                       Node head2)
    {
        Node result = null;
        Node t1 = head1, t2 = head2;
 
        while (t1 != null && t2 != null) {
            if (t1.data < t2.data)
                t1 = t1.next;
            else if (t1.data > t2.data)
                t2 = t2.next;
            else {
                Push(ref result, t2.data);
                t1 = t1.next;
                t2 = t2.next;
            }
        }
 
        return result;
    }
 
    public static void PrintList(Node node)
    {
        while (node != null) {
            Console.Write(node.data + " ");
            node = node.next;
        }
    }
 
    static void Main()
    {
        /* Start with the empty list */
        Node head1 = null;
        Node head2 = null;
        Node intersection_list = null;
        Node union_list = null;
 
        /*create a linked list 11->10->15->4->20 */
        Push(ref head1, 20);
        Push(ref head1, 4);
        Push(ref head1, 15);
        Push(ref head1, 10);
        Push(ref head1, 11);
 
        /*create a linked list 8->4->2->10 */
        Push(ref head2, 10);
        Push(ref head2, 2);
        Push(ref head2, 4);
        Push(ref head2, 8);
 
        /* Sort the above created Linked List */
        MergeSort(ref head1);
        MergeSort(ref head2);
 
        intersection_list = GetIntersection(head1, head2);
        union_list = GetUnion(head1, head2);
 
        Console.WriteLine("First list is:");
        PrintList(head1);
 
        Console.WriteLine("\nSecond list is:");
        PrintList(head2);
 
        Console.WriteLine("\nIntersection list is:");
        PrintList(intersection_list);
 
        Console.WriteLine("\nUnion list is:");
        PrintList(union_list);
 
        Console.ReadLine();
    }
}
 
// This code is contributed by Gaurav_Arora


Javascript




// JavaScript program to find union and intersection of
// two unsored linked lists in O(nlogn) time.
class Node{
    constructor(data){
        this.data = data;
        this.next = null;
    }
}
 
class pair{
    constructor(first, second){
        this.first = first;
        this.second = second;
    }
}
 
// a utility function to insert a node at the beginning of a linked list
function push(head_ref, new_data){
    // allocate and put in the data
    let new_node = new Node(new_data);
     
    // link the old list of 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 Split the nodes of the given list into front
// and back halves. If the length is odd, the extra node
// should go in the front list.
// Uses the fast/slow pointer strategy
function FrontBackSplit(head){
    if(head == null) return head;
     
    let slow = head;
    let fast = head;
    while(fast.next != null && fast.next.next != null){
        slow = slow.next;
        fast = fast.next.next;
    }
    return slow;
}
 
function SortedMerge(a, b){
    let result = null;
    // base case
    if(a == null) return b;
    else if (b == null) return a;
     
    // pick either a or b, and recur
    if(a.data <= b.data){
        result = a;
        result.next = SortedMerge(a.next, b);
    }else{
        result = b;
        result.next = SortedMerge(a, b.next);
    }
    return result;
}
 
// sorts the linked list by changing
// next pointers(not data)
function mergeSort(head){
    // base case
    if(head == null || head.next == null) return head;
     
    // split head into a and b sublists
    let middle = FrontBackSplit(head);
    let nextofmiddle = middle.next;
     
    middle.next = null;
    // recusively sort the variables
    let left = mergeSort(head);
    let right = mergeSort(nextofmiddle);
     
    // answer = merge two sored list together
    return SortedMerge(left, right);
}
 
// function to get the union of two
// linked lists head1 and head2
function getUnion(head1, head2){
    let result = null;
    let t1 = head1;
    let t2 = head2;
     
    // traverse both lists and store the
    // elements in the resultant list
    while(t1 != null && t2 != null){
        // move to the next of first list
        // if its element is smaller
        if(t1.data < t2.data){
            result = push(result, t1.data);
            t1 = t1.next;
        }
        // else move to the next of second list
        else if(t1.data > t2.data){
            result = push(result, t2.data);
            t2 = t2.next;
        }
        // If same then move to the next node
        // in both lists
        else {
            result = push(result, t2.data);
            t1 = t1.next;
            t2 = t2.next;
        }
    }
    /* Print remaining elements of the lists */
    while (t1 != null) {
        result = push(result, t1.data);
        t1 = t1.next;
    }
    while (t2 != null) {
        result = push(result, t2.data);
        t2 = t2.next;
    }
    return result;
}
 
/* Function to get intersection of
two linked lists head1 and head2 */
function getIntersection(head1, head2){
    let result = null;
    let t1 = head1, t2 = head2;
  
    // Traverse both lists and store the same element
    // in the resu1tant list
    while (t1 != null && t2 != null) {
        // Move to the next of first
        // list if smaller
        if (t1.data < t2.data)
            t1 = t1.next;
  
        // Move to the next of second
        // list if it is smaller
        else if (t1.data > t2.data)
            t2 = t2.next;
  
        // If both are same
        else {
            // Store current element in the list
            result = push(result, t2.data);
  
            // Move to the next node of both lists
            t1 = t1.next;
            t2 = t2.next;
        }
    }
  
    // return the resultant list
    return result;
}
 
/* A utility function to print a linked list*/
function printList(node){
    while (node != null) {
        console.log(node.data + " ");
        node = node.next;
    }
}
 
// driver program to test above functions
let head1 = null;
let head2 = null;
let intersection_list = null;
let union_list = null;
 
// create a linked list 11->10->15->4->20
head1 = push(head1, 20);
head1 = push(head1, 4);
head1 = push(head1, 15);
head1 = push(head1, 10);
head1 = push(head1, 11);
 
// create a linked list 8->4->2->10
head2 = push(head2, 10);
head2 = push(head2, 2);
head2 = push(head2, 4);
head2 = push(head2, 8);
 
/* Sort the above created Linked List */
head1 = mergeSort(head1);
head2 = mergeSort(head2);
 
intersection_list = getIntersection(head1, head2);
union_list = getUnion(head1, head2);
 
console.log("First list is ");
printList(head1);
 
console.log("\nSecond list is ");
printList(head2);
 
console.log("\nIntersection list is ");
printList(intersection_list);
 
console.log("\nUnion list is ");
printList(union_list);
 
// THIS CODE IS CONTRIBUTED BY YASH AGARWAL(YASHAGARWAL2852002)


Python3




# Python program to find union and intersection of
# two unsored linked lists in O(nlogn) time.
class Node:
    def __init__(self, data):
        self.data = data
        self.next = None
         
class Pair:
    def __init__(self, first, second):
        self.first = first
        self.second = second
         
# a utility function to insert a node at the beginning of a linked list
def push(head_ref, new_data):
    # allocate and put in the data
    new_node = Node(new_data)
     
    # link the old list of 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 Split the nodes of the given list into front
# and back halves. If the length is odd, the extra node
# should go in the front list.
# Uses the fast/slow pointer strategy
def FrontBackSplit(head):
    if head is None:
        return head
    slow = head
    fast = head
    while fast.next is not None and fast.next.next is not None:
        slow = slow.next
        fast = fast.next.next
    return slow
 
def SortedMerge(a, b):
    result = None
    if a is None:
        return b
    elif b is None:
        return a
         
    # pick either a or b
    if a.data <= b.data:
        result = a
        result.next = SortedMerge(a.next, b)
    else:
        result = b
        result.next = SortedMerge(a, b.next)
    return result
 
# sorts the linked list by changing
# next pointers(not data)
def mergeSort(head):
    # base case
    if head is None or head.next is None:
        return head
         
    # split head into a and b sublists
    middle = FrontBackSplit(head)
    nextofmiddle = middle.next
    middle.next = None
    left = mergeSort(head)
    right = mergeSort(nextofmiddle)
     
    # answer = merge two sored list together
    return SortedMerge(left, right)
 
# function to get the union of two
# linked lists head1 and head2
def getUnion(head1, head2):
    result = None
    t1 = head1
    t2 = head2
     
    # traverse both lists and store the
    # elements in the resultant list
    while t1 is not None and t2 is not None:
        # move to the next of first list
        # if its element is smaller
        if t1.data < t2.data:
            result = push(result, t1.data)
            t1 = t1.next
        # else move to the next of second list
        elif t1.data > t2.data:
            result = push(result, t2.data)
            t2 = t2.next
        # If same then move to the next node
        # in both lists
        else:
            result = push(result, t2.data)
            t1 = t1.next
            t2 = t2.next
    while t1 is not None:
        result = push(result, t1.data)
        t1 = t1.next
    while t2 is not None:
        result = push(result, t2.data)
        t2 = t2.next
    return result
 
# Function to get intersection of
# two linked lists head1 and head2
def getIntersection(head1, head2):
    result = None
    t1 = head1
    t2 = head2
     
    # Traverse both lists and store the same element
    # in the resu1tant list
    while t1 is not None and t2 is not None:
        # Move to the next of first
        # list if smaller
        if t1.data < t2.data:
            t1 = t1.next
             
        # Move to the next of second
        # list if it is smaller
        elif t1.data > t2.data:
            t2 = t2.next
             
        # If both are same
        else:
            # Store current element in the list
            result = push(result, t2.data)
            t1 = t1.next
            t2 = t2.next
    return result
 
# A utility function to print a linked list
def printList(node):
    while node is not None:
        print(str(node.data), end = " ")
        node = node.next
 
# driver program to test above functions
head1 = None
head2 = None
intersection_list = None
union_list = None
 
# create a linked list 11->10->15->4->20
head1 = push(head1, 20)
head1 = push(head1, 4)
head1 = push(head1, 15)
head1 = push(head1, 10)
head1 = push(head1, 11)
 
# create a linked list 8->4->2->10
head2 = push(head2, 10)
head2 = push(head2, 2)
head2 = push(head2, 4)
head2 = push(head2, 8)
 
# Sort the above created Linked List
head1 = mergeSort(head1)
head2 = mergeSort(head2)
intersection_list = getIntersection(head1, head2)
union_list = getUnion(head1, head2)
 
print("First list is ")
printList(head1)
print("\nSecond list is ")
printList(head2)
print("\nIntersection list is ")
printList(intersection_list)
print("\nUnion list is ")
printList(union_list)


Output

First list is 
4 10 11 15 20 
Second list is 
2 4 8 10 
Intersection list is 
10 4 
Union list is 
20 15 11 10 8 4 2 

Complexity Analysis:

  • Time complexity: O(m Log m + n Log n). Time required to sort the lists are n log n and m log m and to find union and intersection linear time is required.
  • Auxiliary Space: O(m+n). If the output is stored then O(m+n) space is required.

In the next post, Method-3 will be discussed i.e. using hashing.



Last Updated : 11 Mar, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads