Fundamentals Snippet: Linked List

Photo by Aida L on Unsplash

Fundamentals Snippet: Linked List

A linked list is a data structure where each element, called a node, contains two parts: the actual data and a reference to the next node. This "next" reference links the nodes together, creating a dynamic sequence of elements. A nice analogy for this is imagining a chain with several links. Each link in the chain represents a node in the linked list. The links are connected to each other, forming a sequence.

Let's try to make a linked list using Python. First, let's take a look in building the fundamental part of a linked list - the Node.

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

We start by initializing a Node class, with data and next attributes. It accepts data as a parameter for it to be stored to its self.data attribute. On the other hand, the self.next attribute is initially defined as None. We've defined the Node as if it's an isolated link, not yet chained in a linked list.

Then we proceed with the LinkedList class:

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

    def insert(self, newNode):
        if self.head:
            current = self.head
            while current.next:
                current = current.next
            current.next = newNode
        else:
            self.head = newNode

The LinkedList class is set to manage the linked list. It initializes the head attribute, which represents the first node of the linked list (hence, the head!). It takes a head parameter, which has a default value of None. The reason behind this has something to do with the only method we defined, which is ---.

The insert method handles the insertion of a new node at the end of the linked list. It takes a newNode parameter, which is an instance of the Node class. The rationale for the conditional statements defined there are as follows:

  • If the linked list is not empty, as proven by checking if there is a head (hence, whether if self.head is truthy!), the method traverses the list starting from the head node using a while loop. Why do we have to traverse the list? Because it is trying to find the last node. As you may recall, we have initiated the next attribute for a node. The method would iterate through the next attributes until it reaches the node with a next attribute of None, which is the last node! Then, it sets the next reference of the last node to the newNode, effectively inserting it at the end of the list.

  • If the linked list is empty, as proven that self.head is None (simply put, the else logic for not meeting the if self.head condition above), the newNode becomes the first node in the list (hence, the head!), so it is assigned to the head attribute. And yes, this is the reason why we set the default value of head as None, to handle cases like this.

This is how our code looks like overall:

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

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

    def insert(self, newNode):
        if self.head:
            current = self.head
            while current.next:
                current = current.next
            current.next = newNode
        else:
            self.head = newNode

Now, to see this code in action, we need to add a display method inside the LinkedList class:

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

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

    def insert(self, newNode):
        if self.head:
            current = self.head
            while current.next:
                current = current.next
            current.next = newNode
        else:
            self.head = newNode

    #added a helper method to display the LinkedList
    def display(self):
        current = self.head
        while current:
            print(current.data, end=' ')
            current = current.next
        print()

We should first create samples of Node, then create a LinkedList(). Then we join all the created nodes by accessing the LinkedList()'s insert method.

# Creating nodes
node1 = Node(10)
node2 = Node(20)
node3 = Node(30)

# Creating a linked list
myList = LinkedList()

# Inserting nodes into the linked list
myList.insert(node1)
myList.insert(node2)
myList.insert(node3)

Finally, we call the display method:

myList.display()

# Output:
# 10 20 30

We can add more features on the LinkedList class by adding more methods or modifying the insert method. I'll try to demonstate in the future how we can reuse this class to solve linked list related algorithm problems.