YouTip LogoYouTip

Python Linked List

## Implementing a Linked List in Python with Sorting and Search Capabilities A **Linked List** is a fundamental linear data structure used in computer science. Unlike arrays or Python's built-in lists, elements in a linked list are not stored in contiguous memory locations. Instead, they are represented as individual **Nodes**. Each node contains two parts: 1. **Data**: The actual value stored in the node. 2. **Next**: A reference (or pointer) to the next node in the sequence. In this tutorial, we will build a Singly Linked List from scratch in Python, implementing essential operations such as appending elements, traversing, searching, and sorting. --- ## Architecture of a Linked List A singly linked list is managed via a `head` pointer, which points to the first node. If the list is empty, the `head` points to `None`. The last node of the list always points to `None` to signify the end of the sequence. ``` β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Data | Nextβ”‚ ───> β”‚ Data | Nextβ”‚ ───> β”‚ Data | Nextβ”‚ ───> None β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## Code Implementation Below is the complete Python implementation of a `Node` class and a `LinkedList` class containing `append`, `display`, `sort`, and `search` methods. ```python class Node: """Represents a single node in the linked list.""" def __init__(self, data): self.data = data # Stores the data payload self.next = None # Reference to the next node, initialized to None class LinkedList: """Represents the linked list structure.""" def __init__(self): self.head = None # Points to the first node of the list def append(self, data): """Appends a new node with the given data to the end of the list.""" new_node = Node(data) # If the list is empty, make the new node the head if not self.head: self.head = new_node return # Traverse to the last node last_node = self.head while last_node.next: last_node = last_node.next # Link the last node to the new node last_node.next = new_node def display(self): """Traverses and prints the entire linked list.""" current = self.head while current: print(current.data, end=" -> ") current = current.next print("None") def sort(self): """ Sorts the elements of the linked list. Extracts data to a Python list, sorts it, and reconstructs the linked list. """ if not self.head: return # Step 1: Extract data from the nodes sorted_list = [] current = self.head while current: sorted_list.append(current.data) current = current.next # Step 2: Sort the extracted data sorted_list.sort() # Step 3: Rebuild the linked list with sorted values self.head = None for item in sorted_list: self.append(item) def search(self, key): """Searches for a specific value in the linked list. Returns True if found.""" current = self.head while current: if current.data == key: return True current = current.next return False # --- Example Usage --- if __name__ == "__main__": # Initialize the linked list ll = LinkedList() # Append elements ll.append(3) ll.append(1) ll.append(4) ll.append(2) print("Original Linked List:") ll.display() # Sort the linked list ll.sort() print("\nSorted Linked List:") ll.display() # Search for elements print("\nSearch Results:") print(f"Is 4 in the list? {ll.search(4)}") print(f"Is 5 in the list? {ll.search(5)}") ``` --- ## Detailed Code Walkthrough ### 1. The `Node` Class The `Node` class is the building block of our linked list. It contains: * `self.data`: Holds the value. * `self.next`: Holds the reference to the next node. It defaults to `None` when a node is first created. ### 2. The `LinkedList` Class The `LinkedList` class manages the nodes and exposes the API for interacting with them: * **`append(data)`**: Adds a node to the end of the list. If the list is empty (`self.head is None`), the new node becomes the head. Otherwise, it traverses the list using a `while` loop until it finds the node where `next` is `None`, then attaches the new node there. * **`display()`**: Iterates through each node starting from `self.head` and prints its data, visually representing the links with `->` arrows. * **`sort()`**: This implementation uses a hybrid approach. It extracts the node values into a standard Python list, utilizes Python's highly optimized Timsort algorithm (`list.sort()`), and then clears and rebuilds the linked list structure in sorted order. * **`search(key)`**: Performs a linear search starting from the `head`. It compares each node's data with the target `key`. If a match is found, it returns `True`; if the end of the list is reached without a match, it returns `False`. --- ## Execution Output When you run the script, you will see the following output: ```text Original Linked List: 3 -> 1 -> 4 -> 2 -> None Sorted Linked List: 1 -> 2 -> 3 -> 4 -> None Search Results: Is 4 in the list? True Is 5 in the list? False ``` --- ## Key Considerations & Complexity Analysis | Operation | Time Complexity | Space Complexity | Description | | :--- | :--- | :--- | :--- | | **Append** | $O(N)$ | $O(1)$ | Requires traversing the entire list to find the end. Can be optimized to $O(1)$ by maintaining a `tail` pointer. | | **Search** | $O(N)$ | $O(1)$ | Requires linear traversal in the worst case. | | **Sort** | $O(N \log N)$ | $O(N)$ | The current approach uses an auxiliary Python list, which requires $O(N)$ extra space but benefits from Python's fast C-implemented sorting. | ### Optimization Tips * **Tail Pointer**: By keeping track of a `self.tail` pointer in the `LinkedList` class, you can optimize the `append` operation from $O(N)$ to $O(1)$. * **In-Place Sorting**: For memory-constrained environments, you can implement in-place sorting algorithms like **Merge Sort** directly on the linked list nodes to achieve $O(N \log N)$ time complexity with $O(1)$ auxiliary space.
← Python Circle Area CircumferenPython Arithmetic Operati β†’