Singly Linked List Implementation in Python


In this article, we will learn what is singly linked list is and its implementation using Python.
The singly linked list is a linear data structure in which each element of the list contains a pointer that points to the next element in the list. Each element in the singly linked list is called a node. Each node has two components: data and a pointer next which points to the next node in the list. 
The first node of the list is called a head, and the last node of the list is called a tail. The last node of the list contains a pointer to the null. Each node in the list can be accessed linearly by traversing through the list from head to tail.

Singly Linked List Implementation in Python

from typing import Anyclass Node:    def __init__(self, data: Any):        self.data = data        self.next = None    def __repr__(self) -> str:        return f"Node({self.data})"class LinkedList:    def __init__(self):               self.head = None    def __iter__(self) -> Any:                node = self.head        while node:            yield node.data            node = node.next    def __len__(self) -> int:        return len(tuple(iter(self)))    def __repr__(self) -> str:        return "->".join([str(item) for item in self])    def __getitem__(self, index: int) -> Any:        if not 0 <= index < len(self):            raise ValueError("list index out of range.")        for i, node in enumerate(self):            if i == index:                return node    # Used to change the data of a particular node    def __setitem__(self, index: int, data: Any) -> None:        if not 0 <= index < len(self):            raise ValueError("list index out of range.")        current = self.head        for i in range(index):            current = current.next        current.data = data    def insert_tail(self, data: Any) -> None:        self.insert_nth(len(self), data)    def insert_head(self, data: Any) -> None:        self.insert_nth(0, data)    def insert_nth(self, index: int, data: Any) -> None:        if not 0 <= index <= len(self):            raise IndexError("list index out of range")        new_node = Node(data)        if self.head is None:            self.head = new_node        elif index == 0:            new_node.next = self.head  # link new_node to head            self.head = new_node        else:            temp = self.head            for _ in range(index - 1):                temp = temp.next            new_node.next = temp.next            temp.next = new_node    def print_list(self) -> None:  # print every node data        print(self)    def delete_head(self) -> Any:        return self.delete_nth(0)    def delete_tail(self) -> Any:  # delete from tail        return self.delete_nth(len(self) - 1)    def delete_nth(self, index: int = 0) -> Any:        if not 0 <= index <= len(self) - 1:  # test if index is valid            raise IndexError("List index out of range.")        delete_node = self.head  # default first node        if index == 0:            self.head = self.head.next        else:            temp = self.head            for _ in range(index - 1):                temp = temp.next            delete_node = temp.next            temp.next = temp.next.next        return delete_node.data    def is_empty(self) -> bool:        return self.head is None    def reverse(self) -> None:        prev = None        current = self.head        while current:            # Store the current node's next node.            next_node = current.next            # Make the current node's next point backwards            current.next = prev            # Make the previous node be the current node            prev = current            # Make the current node the next node (to progress iteration)            current = next_node        # Return prev in order to put the head at the end        self.head = prevdef main():    linked_list = LinkedList()    linked_list.insert_head(input("Inserting 1st at head ").strip())    linked_list.insert_head(input("Inserting 2nd at head ").strip())    print("\nPrint list:")    linked_list.print_list()    linked_list.insert_tail(input("\nInserting 1st at tail ").strip())    linked_list.insert_tail(input("Inserting 2nd at tail ").strip())    print("\nPrint list:")    linked_list.print_list()    print("\nDelete head")    linked_list.delete_head()    print("Delete tail")    linked_list.delete_tail()    print("\nPrint list:")    linked_list.print_list()    print("\nReverse linked list")    linked_list.reverse()    print("\nPrint list:")    linked_list.print_list()    print("\nString representation of linked list:")    print(linked_list)    print("\nReading/changing Node data using indexing:")    print(f"Element at Position 1: {linked_list[1]}")    linked_list[1] = input("Enter New Value: ").strip()    print("New list:")    print(linked_list)    print(f"length of linked_list is : {len(linked_list)}")if __name__ == "__main__":    main()

Output:

Inserting 1st at head 10Inserting 2nd at head 20Print list:20->10Inserting 1st at tail 30Inserting 2nd at tail 40Print list:20->10->30->40Delete headDelete tailPrint list:10->30Reverse linked listPrint list:30->10String representation of linked list:30->10Reading/changing Node data using indexing:Element at Position 1: 10Enter New Value: 50New list:30->50length of linked_list is : 2

Comments