Insert at Beginning of Doubly Linked List in DSA Rust - Time & Space Complexity
We want to understand how long it takes to add a new item at the start of a doubly linked list.
How does the time needed change as the list grows bigger?
Analyze the time complexity of the following code snippet.
struct Node {
data: i32,
prev: Option<*mut Node>,
next: Option>,
}
fn insert_at_beginning(head: &mut Option>, data: i32) {
let mut new_node = Box::new(Node { data, prev: None, next: head.take() });
if let Some(ref mut old_head) = new_node.next {
old_head.prev = Some(&mut *new_node);
}
*head = Some(new_node);
}
This code adds a new node at the start of a doubly linked list, updating pointers accordingly.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Creating and linking one new node.
- How many times: This happens once per insertion, no loops or recursion.
Adding a node at the start always takes the same steps, no matter how big the list is.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 5 steps |
| 100 | About 5 steps |
| 1000 | About 5 steps |
Pattern observation: The number of steps stays the same no matter how large the list grows.
Time Complexity: O(1)
This means adding at the start takes a fixed amount of time, no matter the list size.
[X] Wrong: "Adding at the start takes longer as the list grows because we have to move all nodes."
[OK] Correct: We only change a few pointers at the start; we do not move or touch the other nodes.
Knowing this helps you explain why linked lists are good for quick insertions at the start, a common question in interviews.
"What if we changed to insert at the end of the doubly linked list without a tail pointer? 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 head pointer
The head pointer must be updated to point to this new node, making it the first element.Final Answer:
To add a new node as the first element, updating head pointer -> Option CQuick Check:
Insert at beginning = update head to new node [OK]
- Confusing insertion at beginning with insertion at end
- Not updating the head pointer
- Not adjusting previous pointer of old head
Solution
Step 1: Create new node with prev None and next as current head
The new node's previous pointer should be None because it will be the first node. Its next pointer should point to the current head.Step 2: Update head to new node
After creating the new node, the head pointer must be updated to point to this new node.Final Answer:
let new_node = Box::new(Node { data: val, prev: None, next: head }); head = Some(new_node); -> Option AQuick Check:
New node prev None, next head, update head [OK]
- Setting prev to head instead of None
- Not boxing the new node
- Updating tail instead of head
struct Node {
data: i32,
prev: Option,
next: Option,
}
let mut head = Some(Box::new(Node { data: 2, prev: None, next: None }));
// Insert 1 at beginning
let new_node = Box::new(Node { data: 1, prev: None, next: head });
head = Some(new_node);
// Print list
let mut current = &head;
while let Some(node) = current {
print!("{} -> ", node.data);
current = &node.next;
}
print!("null");Solution
Step 1: Understand insertion
The new node with data 1 is created with next pointing to old head (node with data 2). So list starts with 1, then 2.Step 2: Trace printing loop
Printing starts at head (1), then moves to next (2), then next is None, so ends with null.Final Answer:
1 -> 2 -> null -> Option AQuick Check:
New node at front, list prints 1 then 2 [OK]
- Confusing order of nodes after insertion
- Not updating head pointer
- Printing prev instead of next
let mut head = Some(Box::new(Node { data: 3, prev: None, next: None }));
let new_node = Box::new(Node { data: 1, prev: None, next: head });
head = Some(new_node);
if let Some(ref mut old_head) = head {
old_head.prev = Some(Box::new(Node { data: 1, prev: None, next: None }));
}Solution
Step 1: Check prev pointer update
The code sets old_head.prev to a new node with data 1 instead of linking it to the existing new_node.Step 2: Understand correct linking
Prev pointer should point to the new_node itself, not a new separate node.Final Answer:
Incorrectly creates a new node for prev instead of linking to new_node -> Option BQuick Check:
Prev must link to new_node, not new node copy [OK]
- Creating duplicate nodes instead of linking
- Not using mutable references for modification
- Not updating prev pointer at all
Solution
Step 1: Create new node with prev None and next pointing to old head
The new node is first, so prev is None. Next points to old head (node with 3).Step 2: Update old head's prev pointer to new node and head pointer to new node
Old head's prev must point back to new node. Head pointer must be updated to new node.Final Answer:
Create new node with prev None, next old head; set old head prev to new node; update head to new node -> Option DQuick Check:
New node prev None, next old head; old head prev new node; update head [OK]
- Setting new node prev to old head
- Not updating old head prev pointer
- Not updating head pointer
Ready to prove it?
Pass the test and this pattern moves unknown
