Data Structures and Algorithms (DSA)  

Understanding Linked Lists: Types, Operations, and Real-Life Uses

Introduction

In the world of Data Structures, a Linked List is one of the most fundamental and widely used structures. It provides a flexible way to store and manage data, especially when the number of elements isn’t fixed or when inserting and deleting elements frequently.

Unlike an Array, which stores elements in contiguous memory locations, a Linked List stores elements at different memory locations, connected through links (or pointers). This design makes linked lists more dynamic but also slightly more complex to understand and manage.

What is a Linked List?

A Linked List is a linear data structure where each element, called a node, contains two parts:

  1. Data – The actual value or information to store.

  2. Pointer (Link) – The address (or reference) of the next node in the list.

Together, these nodes form a chain, where each node points to the next.

Example

[10 | next] β†’ [20 | next] β†’ [30 | next] β†’ None

Here, each box (node) holds a value and a pointer to the next node. The last node points to None, which marks the end of the list.

Key Features of Linked Lists

FeatureDescription
Dynamic SizeThe size of a linked list can grow or shrink as needed, unlike arrays which have a fixed size.
Non-Contiguous MemoryElements are stored in scattered memory locations.
Efficient Insertions/DeletionsAdding or removing elements does not require shifting data like arrays do.
Sequential AccessElements can only be accessed sequentially (no direct access by index).
Uses PointersEach node contains a pointer/reference to the next node.

Structure of a Node (in Python)

Here’s how a node can be defined in Python using a simple class:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None  # Pointer to the next node

And a linked list itself can be represented as:

class LinkedList:
    def __init__(self):
        self.head = None  # Start of the linked list

Types of Linked Lists

There are several types of linked lists, each with its own use cases and behavior.

1. Singly Linked List

This is the simplest type, each node points only to the next node. Traversal is possible only in one direction (from head to tail).

Structure Example:

[10 | *] β†’ [20 | *] β†’ [30 | None]

Python Example:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class SinglyLinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            return
        temp = self.head
        while temp.next:
            temp = temp.next
        temp.next = new_node

    def display(self):
        temp = self.head
        while temp:
            print(temp.data, end=" β†’ ")
            temp = temp.next
        print("None")

# Example usage
lst = SinglyLinkedList()
lst.append(10)
lst.append(20)
lst.append(30)
lst.display()

Output:

10 β†’ 20 β†’ 30 β†’ None

2. Doubly Linked List

In this type, each node contains two pointers, one pointing to the next node and another to the previous node.

This allows two-way traversal (forward and backward).

Structure Example:

None ← [10 | * | *] ↔ [20 | * | *] ↔ [30 | * | None]

Python Example:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None
        self.prev = None

class DoublyLinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            return
        temp = self.head
        while temp.next:
            temp = temp.next
        temp.next = new_node
        new_node.prev = temp

    def display_forward(self):
        temp = self.head
        while temp:
            print(temp.data, end=" ↔ ")
            temp = temp.next
        print("None")

3. Circular Linked List

In this type, the last node points back to the first node, forming a circle.
This allows traversal to continue indefinitely unless explicitly stopped.

Structure Example:

[10 | *] β†’ [20 | *] β†’ [30 | *] β†Ί (back to 10)

Python Example:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class CircularLinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            new_node.next = self.head
        else:
            temp = self.head
            while temp.next != self.head:
                temp = temp.next
            temp.next = new_node
            new_node.next = self.head

    def display(self):
        temp = self.head
        if not temp:
            return
        while True:
            print(temp.data, end=" β†’ ")
            temp = temp.next
            if temp == self.head:
                break
        print("(back to head)")

Common Operations on Linked Lists

OperationDescriptionTime Complexity
TraversalVisit each node in the listO(n)
Insertion at BeginningAdd a new node at the startO(1)
Insertion at EndAdd a new node at the endO(n)
Insertion After a NodeInsert after a specific nodeO(1)
DeletionRemove a nodeO(n)
SearchFind a node with specific dataO(n)

Example: Inserting at Beginning

def insert_at_beginning(self, data):
    new_node = Node(data)
    new_node.next = self.head
    self.head = new_node

Example: Deleting a Node

def delete(self, key):
    temp = self.head
    if temp and temp.data == key:
        self.head = temp.next
        return
    prev = None
    while temp and temp.data != key:
        prev = temp
        temp = temp.next
    if temp is None:
        return
    prev.next = temp.next

Advantages of Linked Lists

  1. Dynamic Size – Can grow or shrink at runtime without memory wastage.

  2. Efficient Insertions/Deletions – No need to shift elements like in arrays.

  3. No Predefined Memory Requirement – Memory is allocated as needed.

Disadvantages of Linked Lists

  1. No Random Access – Must traverse nodes one by one.

  2. Extra Memory – Each node needs a pointer/reference field.

  3. Slower Access Time – Takes longer to find an element compared to arrays.

  4. Complex Implementation – Managing pointers requires careful handling.

Real-Life Applications of Linked Lists

  1. Undo/Redo Operations in text editors (Doubly Linked List).

  2. Image Viewer navigation (Next and Previous).

  3. Music Playlists where songs are linked (Circular Linked List).

  4. Browser History (Doubly Linked List – forward and backward navigation).

  5. Memory Management in operating systems.

  6. Implementation of Stacks, Queues, and Hash Tables.

Array vs Linked List

FeatureArrayLinked List
Memory AllocationContiguousNon-contiguous
SizeFixedDynamic
Access TimeO(1)O(n)
Insertion/DeletionExpensive (O(n))Efficient (O(1) for beginning)
Extra MemoryNoneRequired for pointers
Cache PerformanceBetterPoorer

Summary

  • A Linked List is a linear data structure made up of nodes, each containing data and a pointer to the next node.

  • It’s dynamic, efficient for insertions/deletions**, but slower for random access.

  • There are different types: Singly, Doubly, and Circular Linked Lists.

  • Common uses include browser history, playlist navigation, and undo-redo systems.

  • Understanding linked lists is essential for mastering data structures, as many advanced structures (like stacks, queues, graphs) are built using them.