Singly linked list structure in Data Structures Theory - Time & Space Complexity
When working with a singly linked list, it is important to understand how the time needed to perform operations changes as the list grows.
We want to know how the time to find or access elements changes as the list gets longer.
Analyze the time complexity of the following code snippet.
class Node:
def __init__(self, value):
self.value = value
self.next = None
class SinglyLinkedList:
def __init__(self):
self.head = None
def find(self, target):
current = self.head
while current is not None:
if current.value == target:
return True
current = current.next
return False
This code defines a singly linked list and a method to find if a value exists by checking each node one by one.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Looping through each node in the list one by one.
- How many times: Up to once for every node until the target is found or the list ends.
As the list gets longer, the time to find a value grows roughly in direct proportion to the number of nodes.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | Up to 10 checks |
| 100 | Up to 100 checks |
| 1000 | Up to 1000 checks |
Pattern observation: The work grows steadily as the list grows longer, checking each node one after another.
Time Complexity: O(n)
This means the time to find a value grows linearly with the number of nodes in the list.
[X] Wrong: "Finding a value in a singly linked list is as fast as in an array because both store data."
[OK] Correct: Unlike arrays, singly linked lists do not allow direct access by position, so you must check nodes one by one, making it slower for searching.
Understanding how linked lists work and their time costs helps you explain data structure choices clearly and solve problems efficiently.
"What if we added a pointer to the tail node? How would that affect the time complexity of finding a value?"
Practice
singly linked list contain?Solution
Step 1: Understand node structure in singly linked list
Each node stores some data and a pointer to the next node only, not to the previous one.Step 2: Compare options with definition
Data and a pointer to the next node matches the definition exactly. Data and pointers to both next and previous nodes describes a doubly linked list. Options C and D miss the pointer to the next node.Final Answer:
Data and a pointer to the next node -> Option CQuick Check:
Node = data + next pointer [OK]
- Confusing singly linked with doubly linked list
- Thinking nodes have no pointers
- Assuming pointer to previous node exists
Solution
Step 1: Understand the head pointer initialization
The head points to the first node or is None if the list is empty.Step 2: Analyze options
head = None correctly initializes head as None for an empty list. head = head.next tries to move head to next node, which is invalid if list is empty. head = head.prev uses prev pointer which does not exist in singly linked list. head = data assigns data to head, which is incorrect.Final Answer:
head = None -> Option AQuick Check:
Empty list head = None [OK]
- Using prev pointer in singly linked list
- Assigning data directly to head
- Moving head before list has nodes
node1 = Node(data=10, next=node2) node2 = Node(data=20, next=node3) node3 = Node(data=30, next=None) head = node1
What is the data value of
head.next.next?Solution
Step 1: Trace the linked nodes from head
head points to node1 with data 10. head.next points to node2 with data 20. head.next.next points to node3 with data 30.Step 2: Identify the data at head.next.next
The data at node3 is 30.Final Answer:
30 -> Option BQuick Check:
head.next.next.data = 30 [OK]
- Confusing node positions
- Assuming next of last node is not None
- Mixing data values with node references
new_node = Node(data=5) new_node.next = head head = new_node.next
Solution
Step 1: Understand insertion at head
To insert new_node at the start, new_node.next should point to current head, then head should be updated to new_node.Step 2: Analyze the code error
The code sets new_node.next = head correctly, but then sets head = new_node.next, which points to old head, not new_node. This loses the new node as head.Final Answer:
head should be assigned to new_node, not new_node.next -> Option DQuick Check:
head = new_node after insertion [OK]
- Assigning head to new_node.next instead of new_node
- Forgetting to link new_node.next to old head
- Not updating head pointer after insertion
head -> node1 -> node2 -> node3 -> None
Which sequence of pointer changes correctly reverses the list?
Solution
Step 1: Understand reversal of singly linked list
Reversing means changing each node's next pointer to point to the previous node instead of the next.Step 2: Identify correct pointer update sequence
Change each node's next pointer to the previous node, then update head to last node correctly describes reversing pointers and updating head to the last node. Swap data values between nodes without changing pointers only swaps data, not pointers. Set head to None and create a new list with reversed data discards the list unnecessarily. Change each node's next pointer to None breaks links without reversing.Final Answer:
Change each node's next pointer to the previous node, then update head to last node -> Option AQuick Check:
Reverse = reverse pointers + update head [OK]
- Swapping data instead of pointers
- Not updating head after reversal
- Breaking links without reconnecting
Ready to prove it?
Pass the test and this pattern moves unknown
