Linked list of linked list, also known as nested linked lists, is a type of Linked List where each main node stores another full linked list. This structure beats old, plain linked lists. It gives way more flexibility to store and manage complex data. In this article we will learn about the basics of Linked List of Linked List, how to create Linked List of Linked List, its applications, advantages and disadvantages.
Representation of Linked List of Linked List:
A Linked List of Linked list is represented by a pointer to the first node of the linked lists. Similar to the linked list, the first node is called the head. If the multilevel linked list is empty, then the value of head is NULL. Each node in a list consists of at least three parts:
- Data.
- Pointer to the next node.
- Pointer to the child node.
Each node of a multilevel linked list is represented as:
class Node
{
public:
int data;
Node *next;
Node *child;
};
Creating a Linked List of Linked Lists:
Below is the implementation of the multilevel linked list
#include <iostream>
#include <vector>
using namespace std;
// Class to represent the node of the linked list
class Node {
public:
int data;
Node* next;
Node* child;
Node()
{
data = 0;
next = nullptr;
child = nullptr;
}
};
// A function to create a linked list
// with n(size) Nodes returns head pointer
Node* createList(vector<int>& arr, int n)
{
Node* head = nullptr;
Node* tmp = nullptr;
// Traversing the passed array
for (int i = 0; i < n; i++) {
// Creating a Node if the list
// is empty
if (head == nullptr) {
tmp = head = new Node();
}
else {
tmp->next = new Node();
tmp = tmp->next;
}
// Created a Node with data and
// setting child and next pointer
// as NULL.
tmp->data = arr[i];
tmp->next = tmp->child = nullptr;
}
return head;
}
// To print linked list
void printMultiLevelList(Node* head)
{
// While head is not None
while (head != nullptr) {
if (head->child != nullptr) {
printMultiLevelList(head->child);
}
cout << head->data << " ";
head = head->next;
}
}
// Driver code
int main()
{
vector<int> arr1 = { 1, 2, 3 };
vector<int> arr2 = { 5, 6 };
vector<int> arr3 = { 4 };
vector<int> arr4 = { 7, 8, 9 };
// creating Four linked lists
// Passing array and size of array
// as parameters
Node* head1 = createList(arr1, 3);
Node* head2 = createList(arr2, 2);
Node* head3 = createList(arr3, 1);
Node* head4 = createList(arr4, 3);
// Initializing children and next pointers
// as shown in given diagram
head1->child = head2;
head1->next->next->child = head3;
head2->next->child = head4;
// Creating a None pointer.
Node* head = nullptr;
head = head1;
// Function Call to print
printMultiLevelList(head);
// Clean up
delete head1;
delete head2;
delete head3;
delete head4;
return 0;
}
// This code is contributed by Prachi.
class Node {
int data;
Node next;
Node child;
Node(int data) {
this.data = data;
this.next = null;
this.child = null;
}
}
public class Main {
// A function to create a linked list with n (size) Nodes, returns head pointer
static Node createList(int[] arr) {
Node head = null;
Node tmp = null;
// Traversing the passed array
for (int i = 0; i < arr.length; i++) {
// Creating a Node if the list is empty
if (head == null) {
tmp = head = new Node(arr[i]);
} else {
tmp.next = new Node(arr[i]);
tmp = tmp.next;
}
// Created a Node with data and setting child and next pointer as NULL.
tmp.child = null;
}
return head;
}
// To print linked list
static void printMultiLevelList(Node head) {
// While head is not null
while (head != null) {
if (head.child != null) {
printMultiLevelList(head.child);
}
System.out.print(head.data + " ");
head = head.next;
}
}
// Driver code
public static void main(String[] args) {
int[] arr1 = {1, 2, 3};
int[] arr2 = {5, 6};
int[] arr3 = {4};
int[] arr4 = {7, 8, 9};
// creating Four linked lists
// Passing array and size of array as parameters
Node head1 = createList(arr1);
Node head2 = createList(arr2);
Node head3 = createList(arr3);
Node head4 = createList(arr4);
// Initializing children and next pointers as shown in given diagram
head1.child = head2;
head1.next.next.child = head3;
head2.next.child = head4;
// Creating a null pointer.
Node head = null;
head = head1;
// Function Call to print
printMultiLevelList(head);
// Clean up (Java does manual memory management, no cleanup needed in this case)
}
}
# Class to represent the node of the linked list
class Node:
def __init__(self):
self.data = 0
self.next = None
self.child = None
# A function to create a linked list
# with n(size) Nodes returns head pointer
def createList(arr, n):
head = None
tmp = None
# Traversing the passed array
for i in range(n):
# Creating a Node if the list
# is empty
if (head == None):
tmp = head = Node()
else:
tmp.next = Node()
tmp = tmp.next
# Created a Node with data and
# setting child and next pointer
# as NULL.
tmp.data = arr[i]
tmp.next = tmp.child = None
return head
# To print linked list
def printMultiLevelList(head):
# While head is not None
while (head != None):
if (head.child != None):
printMultiLevelList(head.child)
print(head.data, end=" ")
head = head.next
# Driver code
if __name__ == '__main__':
arr1 = [1, 2, 3]
arr2 = [5, 6]
arr3 = [4]
arr4 = [7, 8, 9]
# creating Four linked lists
# Passing array and size of array
# as parameters
head1 = createList(arr1, 3)
head2 = createList(arr2, 2)
head3 = createList(arr3, 1)
head4 = createList(arr4, 3)
# Initializing children and next pointers
# as shown in given diagram
head1.child = head2
head1.next.next.child = head3
head2.next.child = head4
# Creating a None pointer.
head = None
head = head1
# Function Call to print
printMultiLevelList(head)
// Class to represent the node of the linked list
class Node {
constructor() {
this.data = 0;
this.next = null;
this.child = null;
}
}
// A function to create a linked list with n (size) Nodes, returns head pointer
function createList(arr) {
let head = null;
let tmp = null;
// Traversing the passed array
for (let i = 0; i < arr.length; i++) {
// Creating a Node if the list is empty
if (head === null) {
tmp = head = new Node();
} else {
tmp.next = new Node();
tmp = tmp.next;
}
// Created a Node with data and setting child and next pointer as NULL.
tmp.data = arr[i];
tmp.next = tmp.child = null;
}
return head;
}
// To print linked list
function printMultiLevelList(head) {
// While head is not null
while (head !== null) {
if (head.child !== null) {
printMultiLevelList(head.child);
}
console.log(head.data + " ");
head = head.next;
}
}
// Driver code
function main() {
let arr1 = [1, 2, 3];
let arr2 = [5, 6];
let arr3 = [4];
let arr4 = [7, 8, 9];
// creating Four linked lists
// Passing array and size of array as parameters
let head1 = createList(arr1);
let head2 = createList(arr2);
let head3 = createList(arr3);
let head4 = createList(arr4);
// Initializing children and next pointers as shown in given diagram
head1.child = head2;
head1.next.next.child = head3;
head2.next.child = head4;
// Creating a null pointer.
let head = null;
head = head1;
// Function Call to print
printMultiLevelList(head);
// Clean up (JavaScript handles memory management automatically)
}
// Call the main function
main();
Output
5 7 8 9 6 1 2 4 3
Applications of Linked List of Linked List:
- Hierarchical Data Representation: Lists that are linked to other lists form structures for data that has hierarchies. This is useful for folders on computers, business roles, or categories inside categories.
- Sparse Matrix Representation: Sparse matrices are very common in the field of computer science. They often get stored and picked up using lists of lists that are linked together. This way of storing allows for dealing with parts of the matrix that are not zero well. Sparse matrices have many zeros in them so a linked list setup works great.
- Multi-level Data Structures: Some algorithms and data structures, such as skip lists or multi-level caching systems, can benefit from the flexibility and dynamic nature of linked lists of linked lists.
Advantages of Linked List of Linked List:
- Flexibility: Lists connected to other lists are great for complex records with changing nested levels. Some are simple. Yet, others are convoluted, with deep layers.
- Dynamic Size: Unlike arrays or matrices, linked lists of linked lists can dynamically adjust their size without requiring pre-allocation of memory.
- Efficient Insertions and Deletions: Insertions and deletions within a linked list of linked lists can be more efficient compared to arrays or matrices, especially when dealing with large data sets.
Disadvantages of Linked List of Linked List:
- Increased Memory Overhead: Maintaining pointers or references between nodes can result in increased memory overhead compared to contiguous data structures like arrays.
- Slower Access Time: Accessing elements in a linked list of linked lists typically requires traversing multiple levels, which can result in slower access times compared to direct indexing in arrays or matrices.
- Complexity: Managing nested data structures introduces complexity. This is true for linked list concepts, which are unfamiliar to some developers. Implementation and understanding become challenging with nested structures.
Conclusion:
Linked lists of linked lists provides a way to sort data by levels. This approach has upsides, like being able to grow or shrink easy. But it has some downsides too. It needs more memory space than other data types. And finding items inside takes more time. It's key to understand the trade-offs before using linked lists of linked lists in projects.