Reverse a Singly Linked List Iterative in DSA Rust - Time & Space Complexity
We want to understand how the time needed to reverse a linked list changes as the list gets bigger.
Specifically, how does the number of steps grow when we reverse the list one node at a time?
Analyze the time complexity of the following code snippet.
fn reverse_list(mut head: Option>) -> Option> {
let mut prev = None;
while let Some(mut current) = head {
head = current.next.take();
current.next = prev;
prev = Some(current);
}
prev
}
This code reverses a singly linked list by changing the direction of each node's pointer one by one.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The while loop that visits each node once.
- How many times: Exactly once per node, so as many times as there are nodes in the list.
Each node is handled once, so if the list doubles in size, the work doubles too.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps |
| 100 | About 100 steps |
| 1000 | About 1000 steps |
Pattern observation: The number of steps grows directly with the number of nodes.
Time Complexity: O(n)
This means the time to reverse the list grows linearly with the number of nodes.
[X] Wrong: "Reversing a linked list takes more than linear time because of pointer changes."
[OK] Correct: Each node is visited once and its pointer changed once, so the work grows only with the number of nodes, not more.
Understanding this linear time reversal is a key skill that shows you can work with linked lists efficiently and clearly.
"What if we used recursion instead of iteration? How would the time complexity change?"
Practice
Solution
Step 1: Understand the linked list structure
A singly linked list has nodes pointing only to the next node, so reversing means changing these pointers.Step 2: Identify the effect of reversal
Reversing changes the direction so the last node points to null and becomes the new head.Final Answer:
To change the direction of the links so the last node becomes the first -> Option AQuick Check:
Reversing = changing link directions [OK]
- Confusing reversal with sorting
- Thinking reversal removes nodes
- Assuming reversal finds middle node
Solution
Step 1: Understand pointer initialization for reversal
We start with a previous pointer set to None because initially no nodes are reversed.Step 2: Check mutability and value
We need mutable prev to update it during iteration, so 'let mut prev = None;' is correct.Final Answer:
let mut prev = None; -> Option CQuick Check:
Mutable prev starts as None [OK]
- Forgetting mut keyword
- Initializing prev with a new node incorrectly
- Using immutable prev when mutation is needed
struct Node {
val: i32,
next: Option,
}
fn print_list(head: &Option) {
let mut current = head;
while let Some(node) = current {
print!("{} -> ", node.val);
current = &node.next;
}
println!("null");
}
fn reverse_list(mut head: Option) -> Option {
let mut prev = None;
while let Some(mut current) = head {
head = current.next.take();
current.next = prev;
prev = Some(current);
}
prev
}
fn main() {
let node3 = Node { val: 3, next: None };
let node2 = Node { val: 2, next: Some(Box::new(node3)) };
let node1 = Node { val: 1, next: Some(Box::new(node2)) };
let head = Some(Box::new(node1));
let reversed_head = reverse_list(head);
print_list(&reversed_head);
}Solution
Step 1: Trace the reversal process
The list starts as 1 -> 2 -> 3 -> null. The reversal changes links so the last node (3) becomes head.Step 2: Confirm print output after reversal
After reversal, print_list prints nodes from new head: 3 -> 2 -> 1 -> null.Final Answer:
3 -> 2 -> 1 -> null -> Option DQuick Check:
Reversed list prints in reverse order [OK]
- Assuming list prints original order after reversal
- Confusing Option C null with empty list
- Thinking code causes compilation error
fn reverse_list(mut head: Option) -> Option {
let mut prev = None;
while let Some(current) = head {
head = current.next;
current.next = prev;
prev = Some(current);
}
prev
}Solution
Step 1: Understand ownership in Rust linked list
current.next is an Option, but to move it out, .take() is needed to avoid borrowing errors.Step 2: Identify the error in head assignment
head = current.next; tries to move without .take(), causing ownership error. Correct is head = current.next.take();Final Answer:
Missing .take() when assigning head = current.next -> Option BQuick Check:
Use .take() to move ownership safely [OK]
- Ignoring Rust ownership rules
- Making prev immutable by mistake
- Changing loop condition unnecessarily
Solution
Step 1: Reverse the list iteratively
Use the iterative reversal method to get the reversed list with all nodes.Step 2: Filter out even nodes from reversed list
Iterate over reversed list and build a new list skipping nodes with even values.Final Answer:
First reverse the list iteratively, then iterate over reversed list to filter out even nodes by rebuilding a new list -> Option AQuick Check:
Reverse then filter by rebuilding list [OK]
- Trying to filter during reversal causing complexity
- Using recursion when iterative is required
- Using stack unnecessarily increasing space
Ready to prove it?
Pass the test and this pattern moves unknown
