Mastering Linked Lists in Python From zero to hero

Linked Lists in Python
Linked Lists in Python

In the world of programming, data structures play a crucial role in organizing and managing data efficiently. One such fundamental data structure is the Linked List in python.While arrays and lists are common, linked lists provide a unique way to store data, especially when the size of the data is unpredictable or when frequent insertions and deletions are required. In this article, we’ll explore what a linked list is, how it works in Python, and how to implement and manipulate it using Python code.

A linked list is a linear data structure where elements, called nodes, are stored in a sequence. Unlike arrays, where elements are stored in contiguous memory locations, linked lists store each element in a separate object called a node. Each node contains two parts:

  1. Data: The value or data stored in the node.
  2. Reference (or Pointer): A reference to the next node in the sequence.

The last node in the list points to None, indicating the end of the list. This structure allows linked lists to grow or shrink dynamically, making them more flexible than arrays.

Linked Lists in Python come in various forms, each with different characteristics:

  1. Singly Linked List: In this type, each node points to the next node in the sequence. The last node points to None.
  2. Doubly Linked List: Each node in a doubly linked list has two pointers, one to the next node and one to the previous node. This allows traversal in both directions.
  3. Circular Linked List: In a circular linked list, the last node points back to the first node, creating a circular structure.

For this article, we’ll focus on implementing a singly linked list in Python.

To implement a linked list in Python, we’ll start by defining a class for the nodes and then a class for the linked list itself.

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

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

    def is_empty(self):
        return self.head is None

    def append(self, data):
        new_node = Node(data)
        if self.head is None:
            self.head = new_node
            return
        last_node = self.head
        while last_node.next:
            last_node = last_node.next
        last_node.next = new_node

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

    def insert_after_node(self, prev_node, data):
        if not prev_node:
            print("Previous node is not in the list")
            return
        new_node = Node(data)
        new_node.next = prev_node.next
        prev_node.next = new_node

    def delete_node(self, key):
        current_node = self.head

        if current_node and current_node.data == key:
            self.head = current_node.next
            current_node = None
            return

        prev = None
        while current_node and current_node.data != key:
            prev = current_node
            current_node = current_node.next

        if current_node is None:
            return

        prev.next = current_node.next
        current_node = None

    def print_list(self):
        current_node = self.head
        while current_node:
            print(current_node.data, end=" -> ")
            current_node = current_node.next
        print("None")
  1. Node Class: The Node class is the building block of theLinked Lists in Python. It initializes with data and a next pointer that initially points to None.
  2. LinkedList Class: The LinkedList class manages the nodes and provides methods to manipulate the list:
    • __init__: Initializes an empty list with head pointing to None.
    • is_empty: Checks if the list is empty.
    • append: Adds a node with the given data at the end of the list.
    • prepend: Adds a node at the beginning of the list.
    • insert_after_node: Inserts a node after a given node.
    • delete_node: Deletes the first node with the given data.
    • print_list: Prints the entire list in a readable format.

Let’s see how we can use our Linked Lists in Python class to create and manipulate a linked list.

# Create a linked list
linked_list = LinkedList()

# Append nodes
linked_list.append("A")
linked_list.append("B")
linked_list.append("C")
linked_list.print_list()  # Output: A -> B -> C -> None

# Prepend a node
linked_list.prepend("D")
linked_list.print_list()  # Output: D -> A -> B -> C -> None

# Insert after a specific node
linked_list.insert_after_node(linked_list.head.next, "E")
linked_list.print_list()  # Output: D -> A -> E -> B -> C -> None

# Delete a node
linked_list.delete_node("B")
linked_list.print_list()  # Output: D -> A -> E -> C -> None

Advantages:

  1. Dynamic Size: Unlike arrays, Linked Lists in Python can grow and shrink in size dynamically without requiring memory reallocation.
  2. Ease of Insertion/Deletion: Inserting or deleting elements in a linked list is easier compared to arrays, especially when working with large datasets.

Disadvantages:

  1. Memory Overhead: Each node requires extra memory for storing the reference to the next node.
  2. Sequential Access: Linked lists do not allow random access to elements like arrays. To access an element, you need to traverse the list from the beginning.

Let’s delve into some common operations you might need to perform on a Linked Lists in Python:

  1. Reversing a Linked List: Reversing a linked list is a common problem. Let’s see how to do this:
def reverse_list(self):
    prev = None
    current = self.head
    while current:
        next_node = current.next
        current.next = prev
        prev = current
        current = next_node
    self.head = prev
  1. Finding the Middle of a Linked List: You can find the middle of a linked list using a slow and fast pointer technique.
def find_middle(self):
    slow = self.head
    fast = self.head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    return slow.data
  1. Detecting a Loop in a Linked List: A linked list might have a cycle, where a node points back to a previous node. You can detect this using Floyd’s cycle-finding algorithm.
def has_cycle(self):
    slow = self.head
    fast = self.head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow == fast:
            return True
    return False

Linked lists are used in various real-world applications where dynamic data storage and efficient insertion/deletion are required:

  1. Implementing Stacks and Queues: Linked lists are often used to implement stack and queue data structures due to their efficient insertion and deletion operations.
  2. Memory Management: Linked lists are used in operating systems for dynamic memory allocation, where blocks of memory are allocated and deallocated frequently.
  3. Graph Representation: Adjacency lists in graph theory are implemented using linked lists, where each vertex has a linked list of its adjacent vertices.
  4. Browser History: Linked lists can be used to implement a web browser’s history feature, allowing users to move back and forth between visited pages.

Linked lists are a fundamental data structure that provides flexibility in data management. Their dynamic nature allows for efficient insertion and deletion, making them ideal for certain applications. However, they also come with challenges, such as higher memory overhead and sequential access. Understanding linked lists and their operations is crucial for any programmer, as they form the basis for more complex data structures and algorithms.

By implementing linked lists in Python, as demonstrated in this article, you can gain hands-on experience with this essential data structure, enhancing your problem-solving skills and preparing you for more advanced topics in computer science.

What is the difference between a linked list and an array in Python?

An array stores elements in contiguous memory locations, allowing for constant-time access to elements using an index. In contrast, a linked list stores elements in separate nodes, with each node pointing to the next. This means accessing an element in a linked list requires traversal from the head of the list, making access time linear. However, linked lists are more flexible in terms of size, allowing for efficient insertions and deletions without the need for memory reallocation.

When should I use a linked list over a Python list?

You should consider using a linked list when you need a dynamic data structure that can grow and shrink efficiently with frequent insertions and deletions, especially at the beginning or middle of the list. Linked lists are also useful when memory allocation is a concern, as they do not require contiguous memory like Python lists. However, if you need fast access to elements via indexing, a Python list (which is essentially a dynamic array) may be more suitable.

How do I detect and remove a loop in a linked list?

To detect a loop in a linked list, you can use Floyd’s Cycle-Finding Algorithm, which employs two pointers (slow and fast). If the slow pointer and fast pointer meet at some point, a loop exists. To remove the loop, once a loop is detected, reset one pointer to the head and move both pointers one step at a time until they meet again at the start of the loop. The node just before this meeting point is where you should remove the loop by setting its next pointer to None.

Can I use built-in Python data types to create a linked list?

While Python’s built-in list type can perform many of the operations of a linked list, such as appending and removing elements, it is implemented as a dynamic array, not a linked list. If you specifically need a linked list, you would need to implement it yourself using classes, as shown in the article. This custom implementation allows you to have full control over the structure and behavior, such as handling nodes and pointers explicitly, which is not possible with Python’s built-in list.

NOTE: you can also read these articles

2 thoughts on “Mastering Linked Lists in Python From zero to hero”

Leave a Comment