Number of connected components in a doubly linked list

Given a doubly linked list ‘L’ and an array ‘refArr’ of references to the nodes of the doubly linked list ‘L’. Array 'refArr' does not contain any duplicate references and the references are not ORDERED.
m <= total no. of nodes in the doubly linked list where m = size of the reference array.
The task is to find the total number of connected components in the linked list ‘L’.

A ‘connected component’ in linked list ‘L’ is defined as a group of nodes in the list with their references stored in the array ‘refArr’ and are adjacent to each other in the list.

Examples:

Input: L = 5 <-> 2 <-> 10 <-> 1 <-> 3, refArr[] = {5, 10, 3, 1}
Output: 2
Two connected components are 5 and 10 <-> 1 <-> 3.
Since 2 is not included in the reference array, that makes 5 disconnected from the rest of the elements.

Input: L = 1 <-> 7 <-> 10 <-> 5 <-> 4 <-> 2, refArr[] = {5, 2, 7, 1}
Output: Total number of connected components are 3

Explanation:

Let us take a double linked list ‘L’ as { N1 N2 N3 N4 N5 N6 }
and the array ‘refArr’ as [ref_to_nodeN1, ref_to_nodeN4, ref_to_nodeN6, ref_to_nodeN2].

Output :
This set of array ‘refArr’ and linked list ‘L’ contains 3 connected components, which are { [N1, N2], [N4], [N6] } .
It is because references of the nodes N1 and N2 are present in the array ‘refArr’ and they are adjacent to each other in the list ‘L’ whereas N4 and N6 are not adjacent to N1, N2 or to each other. Hence, they form separate components.

Now, let the array ‘refArr’ be modified as [ref_to_nodeN4, ref_to_nodeN6, ref_to_nodeN5].

Output :
This set of array ‘refArr’ and linked list ‘L’ contains 1 connected component, which is { [N4, N5, N6] } .
It is because references of the nodes N4, N5 and N6 are present in the array ‘refArr’ and they are adjacent to each other in the list ‘L’. So, we together form 1 connected component.

Naive Approach: It involves traversing the array ‘refArr’ for each node of the liked list ’L’ and checking whether that element is present in the array or not. Also, maintain a Boolean variable which keeps track of whether the previous node in the linked list is in the array or not. Take a variable ‘cc’ which is initialized to 0 and indicates the no. of connected components in the linked list.
Now, let us consider the multiple cases which occur while traversing:

  • Case 1: If the previous node is in the array and the current node being traversed is also in the array then, the Boolean variable will remain 1 meaning that current node is in array but do not increment the variable ’cc’ since the current node forms a part of component already existing for the previous node.
  • Case 2: If the previous node is not in the array and the current node being traversed is in the array then, update the Boolean variable to mark ‘1’ meaning that current node is in the array and also increment the variable ’cc’ by 1 because the current node forms a new component.
  • Case 3: If the previous node is in the array and the current node being traversed is not in the array then, update the Boolean variable to mark 0 meaning that the current node is not in the array and do not increment the variable ’cc’ since the current node is not a part of any component.
  • Case 4: If the previous node is not in the array and the current node being traversed is also not in the array then, the Boolean variable will remain 0 meaning that current node is not in array and do not increment the variable ’cc’ since the current node is not a part of any component.

Now, after performing one of the 4 cases, move to the next node in the linked list and do the same for that node as well.

Time Complexity: O(n*m), where n = size of the linked list ‘L’ And, m = size of the reference array ‘refArr’.
Space Complexity: O(1)

Better Approach: This approach involves the use of unordered_set. Take a variable ‘connectedComponents’ which is initialized to 0. connectedComponents indicates the number of connected components in the linked list.
Now for each element in reference array ‘refArr’:

  1. Add reference stored in the array to an unordered_set ‘refSet’.
    • Check if the current node’s previous or next siblings are already present in the set ‘refSet’.

    • If both previous and next siblings are present, then decrement the variable ‘connectedComponents’ by 1 which means that we have closed a gap between two components, so we must decrement the incorrectly counted components.
    • If only one of the previous and next siblings is present in the set, then no updating is done to the no. of components.
    • If none of the previous and next siblings is present in the set, then we must increment the incorrectly counted components because now, the current node forms a new component.

Below is the implementation of the above approach:

filter_none

edit
close

play_arrow

link
brightness_4
code

// A C++ program to find number 
// of Connected Components in a doubly linked list.
#include <bits/stdc++.h>
using namespace std;
  
// Node of the doubly linked list
struct Node {
    int data;
    struct Node* next;
    struct Node* prev;
};
  
// Function to find number of connected
// components using a doubly linked list
// and a reference array
int func_connComp(struct Node** head_ref,
                  vector<struct Node*> refArr, int n)
{
    // Base case when the doubly
    // linked list is empty
    if (head_ref == NULL) {
        return 0;
    }
  
    // Initialise connectedComponents to zero
    int connectedComponents = 0;
  
    // Initialise an unordered set
    unordered_set<struct Node*> refSet;
  
    // Push the first element of the
    // refArr in the refSet and
    // set the connectedComponents to 1
    refSet.insert(refArr[0]);
    connectedComponents++;
  
    // Loop over all the elements of the refArr
    for (int i = 1; i < n; i++) {
  
        // insert each reference node to the refSet
        refSet.insert(refArr[i]);
  
        // If the reference node is the head of the linked list
        if (refArr[i]->prev == NULL) {
  
            // when next sibling of the head node is
            // not in the refSet
            if (refSet.find(refArr[i]->next) == refSet.end()) {
                connectedComponents++;
            }
        }
  
        // If the reference node is the
        // last node of the linked list*/
        else if (refArr[i]->next == NULL) {
  
            // when previous sibling of the
            // node is not in the refSet
            if (refSet.find(refArr[i]->next) == refSet.end()) {
                connectedComponents++;
            }
        }
  
        // the case when both previous and
        // next siblings of the current node
        // are in the refSet
        else if (refSet.find(refArr[i]->prev) != refSet.end()
                 && refSet.find(refArr[i]->next) != refSet.end()) {
            connectedComponents--;
        }
  
        /*the case when previous and next 
        // siblings of the current node 
        // are not in the refSet*/
        else if (refSet.find(refArr[i]->prev) == refSet.end()
                 && refSet.find(refArr[i]->next) == refSet.end()) {
            connectedComponents++;
        }
    }
    return connectedComponents;
}
  
// Function to insert a node at the
// beginging of the Doubly Linked List
Node* push(struct Node** head_ref, int new_data)
{
    /* allocate node */
    struct Node* new_node = new Node;
  
    struct Node* current_node = new_node;
    /* put in the data */
    new_node->data = new_data;
  
    /* since we are adding at the begining, 
    prev is always NULL */
    new_node->prev = NULL;
  
    /* link the old list off the new node */
    new_node->next = (*head_ref);
  
    /* change prev of head node to new node */
    if ((*head_ref) != NULL)
        (*head_ref)->prev = new_node;
  
    /* move the head to point to the new node */
    (*head_ref) = new_node;
  
    return current_node;
}
  
// Function to print nodes in a given
// doubly linked list
void printList(struct Node* node)
{
    while (node != NULL) {
        printf("%d ", node->data);
        node = node->next;
    }
}
  
// Driver code
int main()
{
  
    // Start with the empty list
    struct Node* head = NULL;
  
    // Let us create a linked list to test
    // the functions so as to find number
    // of Connected Components Created a
    // doubly linked list: 1 <-> 7 <-> 10 <-> 5 <-> 4 <-> 2
    struct Node* ref_to_nodeN2 = push(&head, 2);
    struct Node* ref_to_nodeN4 = push(&head, 4);
    struct Node* ref_to_nodeN5 = push(&head, 5);
    struct Node* ref_to_nodeN10 = push(&head, 10);
    struct Node* ref_to_nodeN7 = push(&head, 7);
    struct Node* ref_to_nodeN1 = push(&head, 1);
  
    vector<struct Node*> refArr{ ref_to_nodeN5,
                                         ref_to_nodeN2, ref_to_nodeN7, ref_to_nodeN1 };
  
    // This function will return the number
    // of connected components of doubly linked list
    int connectedComponents = func_connComp(&head, refArr, 4);
  
    cout << "Total number of connected components are "
         << connectedComponents << endl;
  
    return 0;
}

chevron_right


Output:

Total number of connected components are 3

Time Complexity: O(m)
Space Complexity: O(m) Where, m = size of the reference array ‘refArr’



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.