Day 8: Singly Linked Lists - Implementation and Basic Operations
Table of Contents
Singly Linked Lists - Implementation and Basic Operations #
Welcome to Day 8 of our 60 Days of Coding Algorithm Challenge! Today, we’ll dive deeper into singly linked lists, implementing a more comprehensive version and exploring various operations.
Singly Linked List Structure #
A singly linked list consists of nodes where each node contains data and a pointer to the next node. The last node points to None, indicating the end of the list.
class Node:
def __init__(self, data):
self.data = data
self.next = None
Implementing a Singly Linked List #
Let’s implement a singly linked list with several basic operations:
class SinglyLinkedList:
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.is_empty():
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
def prepend(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
def delete(self, data):
if self.is_empty():
return
if self.head.data == data:
self.head = self.head.next
return
current = self.head
while current.next and current.next.data != data:
current = current.next
if current.next:
current.next = current.next.next
def search(self, data):
current = self.head
while current:
if current.data == data:
return True
current = current.next
return False
def display(self):
elements = []
current = self.head
while current:
elements.append(str(current.data))
current = current.next
print(" -> ".join(elements))
Basic Operations Explained #
- is_empty(): Checks if the list is empty.
- append(data): Adds a new node with the given data to the end of the list.
- prepend(data): Adds a new node with the given data to the beginning of the list.
- delete(data): Removes the first occurrence of a node with the given data.
- search(data): Searches for a node with the given data and returns True if found.
- display(): Prints all elements in the list.
Time Complexity Analysis #
- Append: O(n) - We need to traverse to the end of the list.
- Prepend: O(1) - We simply add to the head.
- Delete: O(n) - In the worst case, we need to traverse the entire list.
- Search: O(n) - We may need to traverse the entire list to find an element.
Example Usage #
Let’s see how to use our SinglyLinkedList class:
# Create a new linked list
my_list = SinglyLinkedList()
# Append elements
my_list.append(1)
my_list.append(2)
my_list.append(3)
my_list.display() # Output: 1 -> 2 -> 3
# Prepend an element
my_list.prepend(0)
my_list.display() # Output: 0 -> 1 -> 2 -> 3
# Search for elements
print(my_list.search(2)) # Output: True
print(my_list.search(4)) # Output: False
# Delete an element
my_list.delete(2)
my_list.display() # Output: 0 -> 1 -> 3
Common Interview Questions #
- Reverse a Linked List: Can you implement a method to reverse the linked list in-place?
- Detect a Cycle: How would you detect if a linked list has a cycle?
- Find the Middle Node: Can you find the middle node of the linked list in one pass?
Exercise #
- Implement a method
insert_after(self, target_data, new_data)
that inserts a new node withnew_data
after the first occurrence of a node withtarget_data
. - Write a method
length(self)
that returns the number of nodes in the linked list. - Implement a method
remove_duplicates(self)
that removes all duplicate nodes from the linked list.
Summary #
Today, we’ve implemented a more comprehensive singly linked list and explored its basic operations. Understanding these operations and their time complexities is crucial for using linked lists effectively in various algorithms.
Tomorrow, we’ll dive into doubly linked lists and compare them with singly linked lists. We’ll also explore some more advanced linked list problems. Stay tuned!