Insert at Beginning Head Insert in DSA Rust - Time & Space Complexity
We want to understand how long it takes to add a new item at the start of a linked list.
How does the time needed change as the list grows?
Analyze the time complexity of the following code snippet.
struct Node {
value: i32,
next: Option>,
}
fn insert_at_head(head: &mut Option>, val: i32) {
let new_node = Box::new(Node { value: val, next: head.take() });
*head = Some(new_node);
}
This code adds a new node at the start of a singly linked list by adjusting the head pointer.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Creating a new node and updating the head pointer.
- How many times: This happens once per insertion, no loops or traversals involved.
Adding a node at the start takes the same steps no matter how big the list is.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 5 steps |
| 100 | 5 steps |
| 1000 | 5 steps |
Pattern observation: The number of steps stays constant as the list grows.
Time Complexity: O(1)
This means adding at the start takes the same short time no matter how many items are in the list.
[X] Wrong: "Adding at the start takes longer as the list grows because we must move all nodes."
[OK] Correct: We only change the head pointer and the new node's next link; no other nodes move or change.
Knowing that head insertion is quick helps you choose the right method when speed matters in linked list operations.
"What if we changed to insert at the end of the list? How would the time complexity change?"
Practice
Solution
Step 1: Understand the operation
Inserting at the beginning means adding a new node before the current first node.Step 2: Effect on linked list
The new node becomes the head, pushing existing nodes after it.Final Answer:
Adds a new node at the start of the list -> Option AQuick Check:
Insert at beginning = Add node at start [OK]
- Confusing insert at beginning with insert at end
- Thinking it deletes nodes
- Assuming it modifies middle nodes
Solution
Step 1: Understand Rust linked list insertion
In Rust, to insert at head, create a new node with next pointing to current head, then update head.Step 2: Match syntax
self.head = Some(Box::new(Node { data, next: self.head.take() })); uses Some(Box::new(Node { data, next: self.head.take() })) which correctly sets new node's next to old head.Final Answer:
self.head = Some(Box::new(Node { data, next: self.head.take() })); -> Option AQuick Check:
Rust head insert = new node points to old head [OK]
- Using push or append on Option type
- Not using Box::new for heap allocation
- Forgetting to update head pointer
let mut list = LinkedList::new(); list.insert_at_beginning(10); list.insert_at_beginning(20); list.insert_at_beginning(30); list.print();Assuming print() shows nodes from head to tail.
Solution
Step 1: Trace insertions
First insert 10 at beginning: list = 10 -> null Second insert 20 at beginning: list = 20 -> 10 -> null Third insert 30 at beginning: list = 30 -> 20 -> 10 -> nullStep 2: Confirm print output
Print shows from head to tail, so output is 30 -> 20 -> 10 -> null.Final Answer:
30 -> 20 -> 10 -> null -> Option CQuick Check:
Last inserted at head appears first [OK]
- Assuming insertion adds at tail
- Reading list backwards
- Confusing print order
fn insert_at_beginning(&mut self, data: i32) {
let new_node = Box::new(Node { data, next: self.head });
self.head = Some(new_node);
}Solution
Step 1: Understand ownership rules
self.head is an Option, so assigning it directly to next moves ownership, which is not allowed without .take().Step 2: Correct usage
Using self.head.take() moves ownership out safely, allowing new_node.next to own old head.Final Answer:
self.head is an Option and needs to be taken with .take() to move ownership -> Option DQuick Check:
Use .take() to move Option ownership safely [OK]
- Assigning Option without .take()
- Ignoring Rust ownership rules
- Using wrong data types
Solution
Step 1: Handle empty and non-empty list uniformly
Using self.head.take() moves the current head out safely whether it is None or Some(node).Step 2: Create new node with next as old head
Assign new node as head with next pointing to old head, no cloning needed.Final Answer:
Use self.head = Some(Box::new(Node { data, next: self.head.take() })) to move ownership safely -> Option BQuick Check:
Use .take() for safe ownership transfer in insert [OK]
- Appending at tail instead of head
- Cloning nodes unnecessarily
- Using unsafe code without need
Ready to prove it?
Pass the test and this pattern moves unknown
