A Generalized Linked List L, is defined as a finite sequence of n>=0 elements, l1, l2, l3, l4, ..., ln, such that li are either item or the list of items. Thus L = (l1, l2, l3, l4, ..., ln) where n is total number of nodes in the list.
To represent a list of items there are certain assumptions about the node structure.
- Flag = 1 implies that down pointer exists
- Flag = 0 implies that next pointer exists
- Data means the item.
- Down pointer is the address of node which is down of the current node
- Next pointer is the address of node which is attached as the next node
Why Generalized Linked List? Generalized linked lists are used because although the efficiency of polynomial operations using linked list is good but still, the disadvantage is that the linked list is unable to use multiple variable polynomial equation efficiently. It helps us to represent multi-variable polynomial along with the list of elements.
Example of Generalized Linked List - {List representation} ( a, (b, c), d) - O(n) Time and O(n) Space
C++
// Representation of GLL "(a, (b, c), d)"
// in C++
#include <iostream>
using namespace std;
// Node structure for GLL
struct Node {
// 0 for data, 1 for down pointer
int flag;
// Union to store data or down pointer
union {
// For variable or coefficient
char data;
// For sublist
Node* down;
};
// Next pointer in the same list
Node* next;
// Constructor for data node
Node(char value) {
// Indicate it is a data node
flag = 0;
data = value;
next = nullptr;
}
// Constructor for down pointer node
Node(Node* downPtr) {
// Indicate it is a down pointer
flag = 1;
down = downPtr;
next = nullptr;
}
};
// Function to print the GLL
void printGLL(Node* head) {
cout << "(";
while (head != nullptr) {
if (head->flag == 0) {
cout << head->data;
}
else if (head->flag == 1) {
printGLL(head->down);
}
if (head->next != nullptr) {
cout << ", ";
}
head = head->next;
}
cout << ")";
}
int main() {
// Create nodes b and c
Node* b = new Node('b');
Node* c = new Node('c');
b->next = c;
// Create a sublist starting with b
Node* subList = new Node(b);
// Create node a and link it to subList
Node* a = new Node('a');
a->next = subList;
// Create node d and link it to subList
Node* d = new Node('d');
subList->next = d;
// Print the GLL in the desired format
printGLL(a);
return 0;
}
C
// Representation of GLL "(a, (b, c), d)"
// in C
#include <stdio.h>
#include <stdlib.h>
// Node structure for GLL
struct Node {
// 0 for data, 1 for down pointer
int flag;
// Union to store data or down pointer
union {
// For variable or coefficient
char data;
// For sublist
struct Node* down;
};
// Next pointer in the same list
struct Node* next;
};
// Function to print the GLL
void printGLL(struct Node* head) {
printf("(");
while (head != NULL) {
if (head->flag == 0) {
printf("%c", head->data);
} else if (head->flag == 1) {
printGLL(head->down);
}
if (head->next != NULL) {
printf(", ");
}
head = head->next;
}
printf(")");
}
// Function to create a new node with data
struct Node* createNodeData(char value) {
struct Node* newNode
= (struct Node*)malloc(sizeof(struct Node));
newNode->flag = 0;
newNode->data = value;
newNode->next = NULL;
return newNode;
}
// Function to create a new node with down pointer
struct Node* createNodeDown(struct Node* downPtr) {
struct Node* newNode
= (struct Node*)malloc(sizeof(struct Node));
newNode->flag = 1;
newNode->down = downPtr;
newNode->next = NULL;
return newNode;
}
int main() {
// Create nodes b and c
struct Node* b = createNodeData('b');
struct Node* c = createNodeData('c');
b->next = c;
// Create a sublist starting with b
struct Node* subList = createNodeDown(b);
// Create node a and link it to subList
struct Node* a = createNodeData('a');
a->next = subList;
// Create node d and link it to subList
struct Node* d = createNodeData('d');
subList->next = d;
// Print the GLL in the desired format
printGLL(a);
return 0;
}
Java
// Representation of GLL "(a, (b, c), d)"
// in JAVA
class Node {
int flag; // 0 for data, 1 for down pointer
// Data for variable or coefficient
char data;
// Down pointer for sublist
Node down;
// Next pointer in the same list
Node next;
// Constructor for data node
Node(char data) {
this.flag = 0;
this.data = data;
this.next = null;
}
// Constructor for down pointer node
Node(Node down) {
this.flag = 1;
this.down = down;
this.next = null;
}
}
public class GfG {
// Function to print the GLL
static void printGLL(Node head) {
System.out.print("(");
while (head != null) {
if (head.flag == 0) {
System.out.print(head.data);
}
else if (head.flag == 1) {
printGLL(head.down);
}
if (head.next != null) {
System.out.print(", ");
}
head = head.next;
}
System.out.print(")");
}
public static void main(String[] args) {
// Create nodes b and c
Node b = new Node('b');
Node c = new Node('c');
b.next = c;
// Create a sublist starting with b
Node subList = new Node(b);
// Create node a and link it to subList
Node a = new Node('a');
a.next = subList;
// Create node d and link it to subList
Node d = new Node('d');
subList.next = d;
// Print the GLL in the desired format
printGLL(a);
}
}
Python
# Representation of GLL "(a, (b, c), d)"
# in Python
class Node:
# Constructor for data or down pointer node
def __init__(self, flag, data=None, down=None):
# 0 for data, 1 for down pointer
self.flag = flag
# For variable or coefficient
self.data = data
# Down pointer to another list
self.down = down
# Next pointer in the same list
self.next = None
# Function to print the GLL
def print_gll(head):
print("(", end="")
while head:
if head.flag == 0:
print(head.data, end="")
elif head.flag == 1:
print_gll(head.down)
if head.next:
print(", ", end="")
head = head.next
print(")", end="")
if __name__ == "__main__":
# Create nodes b and c
b = Node(0, data='b')
c = Node(0, data='c')
b.next = c
# Create a sublist starting with b
sub_list = Node(1, down=b)
# Create node a and link it to subList
a = Node(0, data='a')
a.next = sub_list
# Create node d and link it to subList
d = Node(0, data='d')
sub_list.next = d
# Print the GLL in the desired format
print_gll(a)
C#
// Representation of GLL "(a, (b, c), d)"
// in C#
using System;
class Node {
// 0 for data, 1 for down pointer
public int Flag;
// Data for variable or coefficient
public char Data;
// Down pointer for sublist
public Node Down;
// Next pointer in the same list
public Node next;
// Constructor for data node
public Node(char data) {
this.Flag = 0;
this.Data = data;
this.next = null;
}
// Constructor for down pointer node
public Node(Node down) {
this.Flag = 1;
this.Down = down;
this.next = null;
}
}
class GfG {
static void PrintGLL(Node head) {
Console.Write("(");
while (head != null) {
if (head.Flag == 0) {
Console.Write(head.Data);
}
else if (head.Flag == 1) {
PrintGLL(head.Down);
}
if (head.next != null) {
Console.Write(", ");
}
head = head.next;
}
Console.Write(")");
}
static void Main() {
// Create nodes b and c
Node b = new Node('b');
Node c = new Node('c');
b.next = c;
// Create a sublist starting with b
Node subList = new Node(b);
// Create nodes a and d
Node a = new Node('a');
Node d = new Node('d');
// Link a to subList and d
a.next = subList;
subList.next = d;
// Print the generalized linked list
PrintGLL(a);
}
}
JavaScript
// Representation of GLL "(a, (b, c), d)"
// in Javascript
class Node {
// Constructor for data or down pointer node
constructor(flag, data = null, down = null) {
// 0 for data, 1 for down pointer
this.flag = flag;
// For variable or coefficient
this.data = data;
// Down pointer to another list
this.down = down;
// Next pointer in the same list
this.next = null;
}
}
// Function to print the GLL
function printGLL(head) {
let result = "";
function buildString(node) {
result += "(";
while (node !== null) {
if (node.flag === 0) {
result += node.data;
}
else if (node.flag === 1) {
buildString(node.down);
}
if (node.next !== null) {
result += ", ";
}
node = node.next;
}
result += ")";
}
buildString(head);
console.log(result);
}
// Create nodes b and c
let b = new Node(0, 'b');
let c = new Node(0, 'c');
b.next = c;
// Create a sublist starting with b
let subList = new Node(1, null, b);
// Create node a and link it to subList
let a = new Node(0, 'a');
a.next = subList;
// Create node d and link it to subList
let d = new Node(0, 'd');
subList.next = d;
// Print the GLL in the desired format
printGLL(a);
When first field is 0, it indicates that the second field is variable. If first field is 1 means the second field is a down pointer, means some list is starting.
Polynomial Representation using Generalized Linked List
The typical node structure will be: 
- Here Flag = 0 means variable is present
- Flag = 1 means down pointer is present
- Flag = 2 means coefficient and exponent is present
Example: 9x5 + 7x4y + 10xz
In the above example the head node is of variable x. The temp node shows the first field as 2 means coefficient and exponent are present.
Since temp node is attached to head node and head node is having variable x, temp node having coefficient = 9 and exponent = 5. The above two nodes can be read as 9x5.
Similarly, in the above figure, the node temp1 can be read as x4.
- The flag field is 1 means down pointer is there
- temp2 = y
- temp3 = coefficient = 7
- exponent = 1
- flag = 2 means the node contains coefficient and exponent values.
- temp2 is attached to temp3 this means 7y1 and temp2 is also attached to temp1 means
- temp1 x temp2
- x4 x 7y1 = 7x4y1 value is represented by above figure
Advantages of Generalized Linked List
- GLLs can represent both linear and hierarchical structures, making them suitable for complex data representation. This flexibility is useful in applications like document processing or nested data formats.
- The recursive nature of GLLs makes them naturally suited for representing hierarchical relationships. This can simplify algorithms that process nested data, as the recursive structure mirrors the data’s hierarchy.
- GLLs can easily grow or shrink as needed since they use dynamic memory allocation. This flexibility allows for efficient handling of varying amounts of data.
- GLLs can handle arbitrary levels of nesting, which is beneficial when dealing with deeply nested structures like mathematical expressions or complex document formats.
Disadvantages of Generalized Linked List
- Implementing and managing GLLs can be more complex compared to simple linked lists or arrays. The recursive nature requires careful handling to avoid issues like infinite recursion or excessive memory use.
- The additional pointers (Next and Down) and the need for multiple node types can introduce overhead in terms of both memory and processing. Each node typically requires extra space for pointers and may involve additional operations during traversal.
- Traversing GLLs can be more complex than traversing simple linear lists. Handling nested structures requires more sophisticated algorithms, which can be error-prone and harder to optimize.
- The recursive nature can lead to performance issues, especially in cases where deep nesting is involved. Recursive operations might lead to high memory usage and slower performance compared to more straightforward data structures.
- Debugging GLLs can be challenging due to their complex structure. Visualizing and understanding the relationships between nodes, especially in deeply nested scenarios, can be difficult.
Similar Reads
DSA Tutorial - Learn Data Structures and Algorithms DSA (Data Structures and Algorithms) is the study of organizing data efficiently using data structures like arrays, stacks, and trees, paired with step-by-step procedures (or algorithms) to solve problems effectively. Data structures manage how data is stored and accessed, while algorithms focus on
7 min read
Quick Sort QuickSort is a sorting algorithm based on the Divide and Conquer that picks an element as a pivot and partitions the given array around the picked pivot by placing the pivot in its correct position in the sorted array. It works on the principle of divide and conquer, breaking down the problem into s
12 min read
Merge Sort - Data Structure and Algorithms Tutorials Merge sort is a popular sorting algorithm known for its efficiency and stability. It follows the divide-and-conquer approach. It works by recursively dividing the input array into two halves, recursively sorting the two halves and finally merging them back together to obtain the sorted array. Merge
14 min read
Bubble Sort Algorithm Bubble Sort is the simplest sorting algorithm that works by repeatedly swapping the adjacent elements if they are in the wrong order. This algorithm is not suitable for large data sets as its average and worst-case time complexity are quite high.We sort the array using multiple passes. After the fir
8 min read
Data Structures Tutorial Data structures are the fundamental building blocks of computer programming. They define how data is organized, stored, and manipulated within a program. Understanding data structures is very important for developing efficient and effective algorithms. What is Data Structure?A data structure is a st
2 min read
Breadth First Search or BFS for a Graph Given a undirected graph represented by an adjacency list adj, where each adj[i] represents the list of vertices connected to vertex i. Perform a Breadth First Search (BFS) traversal starting from vertex 0, visiting vertices from left to right according to the adjacency list, and return a list conta
15+ min read
Binary Search Algorithm - Iterative and Recursive Implementation Binary Search Algorithm is a searching algorithm used in a sorted array by repeatedly dividing the search interval in half. The idea of binary search is to use the information that the array is sorted and reduce the time complexity to O(log N). Binary Search AlgorithmConditions to apply Binary Searc
15 min read
Insertion Sort Algorithm Insertion sort is a simple sorting algorithm that works by iteratively inserting each element of an unsorted list into its correct position in a sorted portion of the list. It is like sorting playing cards in your hands. You split the cards into two groups: the sorted cards and the unsorted cards. T
9 min read
Dijkstra's Algorithm to find Shortest Paths from a Source to all Given a weighted undirected graph represented as an edge list and a source vertex src, find the shortest path distances from the source vertex to all other vertices in the graph. The graph contains V vertices, numbered from 0 to V - 1.Note: The given graph does not contain any negative edge. Example
12 min read
Selection Sort Selection Sort is a comparison-based sorting algorithm. It sorts an array by repeatedly selecting the smallest (or largest) element from the unsorted portion and swapping it with the first unsorted element. This process continues until the entire array is sorted.First we find the smallest element an
8 min read