📖 Scenario: You are managing a playlist of songs using a doubly linked list. Each song is a node with a title and links to the previous and next songs. You want to remove the first song from the playlist when you finish listening to it.
🎯 Goal: Build a doubly linked list of songs, then delete the first song from the list, and finally print the updated playlist.
📋 What You'll Learn
Create a doubly linked list with exactly three songs: "Song1", "Song2", "Song3"
Create a variable called head that points to the first node
Write a function called delete_from_beginning that removes the first node from the list
Print the playlist after deletion in the format: Song2 <-> Song3 <-> null
💡 Why This Matters
🌍 Real World
Doubly linked lists are used in music players, browsers, and other apps to manage sequences where you can move forward and backward easily.
💼 Career
Understanding linked lists and how to modify them is a key skill for software developers working with low-level data structures or performance-critical applications.
Progress0 / 4 steps
1
Create the Doubly Linked List with Three Songs
Create a struct called Node with fields title: String, prev: Option>, and next: Option>. Then create three nodes with titles "Song1", "Song2", and "Song3" linked as a doubly linked list. Finally, create a variable called head that points to the first node.
DSA Rust
Hint
Define the Node struct with title, prev, and next. Create nodes from last to first so you can link them properly. Use Option> for links.
2
Add a Function to Delete the First Node
Add a function called delete_from_beginning that takes head: Option> and returns Option>. This function should remove the first node and return the new head of the list.
DSA Rust
Hint
Use match on head. If None, return None. If Some(node), take node.next as new head and set its prev to None.
3
Delete the First Node from the List
Call the function delete_from_beginning with the variable head and store the result back in head.
DSA Rust
Hint
Assign the result of delete_from_beginning(head) back to head.
4
Print the Updated Playlist
Write a loop to print the titles of the songs in the list starting from head. Print each title followed by " <-> ". After the last song, print "null".
DSA Rust
Hint
Use a while let loop to traverse from head. Print each title followed by " <-> ". After the loop, print "null".
Practice
(1/5)
1. What happens to the head pointer when you delete the first node from a doubly linked list?
easy
A. It points to the last node
B. It moves to the next node in the list
C. It becomes null immediately
D. It remains unchanged
Solution
Step 1: Understand the role of head in a doubly linked list
The head pointer always points to the first node in the list.
Step 2: Effect of deleting the first node
When the first node is deleted, the head must move to the next node to keep the list accessible.
Final Answer:
It moves to the next node in the list -> Option B
Quick Check:
Deleting first node updates head to next node [OK]
Hint: Head always points to first node; update it after deletion [OK]
Common Mistakes:
Not updating head pointer after deletion
Setting head to null without checking list length
Confusing head with tail pointer
2. Which of the following Rust code snippets correctly deletes the first node from a doubly linked list?
easy
A. if let Some(mut node) = head.take() { head = node.next.take(); if let Some(ref mut new_head) = head { new_head.prev = None; } }
B. head = head.next; head.prev = None;
C. head = None; tail = None;
D. head.prev = None; head = head.next;
Solution
Step 1: Analyze safe Rust deletion pattern
if let Some(mut node) = head.take() { head = node.next.take(); if let Some(ref mut new_head) = head { new_head.prev = None; } } uses take() to safely remove the first node and updates head and prev pointers correctly.
Step 2: Check other options for errors
head = head.next; head.prev = None; tries to access head.next without handling Option. head = None; tail = None; deletes entire list incorrectly. head.prev = None; head = head.next; accesses head.prev before updating head, causing error.
Final Answer:
Option A code snippet -> Option A
Quick Check:
Safe pointer update with take() = if let Some(mut node) = head.take() { head = node.next.take(); if let Some(ref mut new_head) = head { new_head.prev = None; } } [OK]
Hint: Use take() to safely remove and update pointers [OK]
Common Mistakes:
Ignoring Option unwrap safety
Not updating prev pointer of new head
Setting head to None without checking
3. Given the following Rust code for a doubly linked list deletion from beginning, what will be the printed list after deletion?
struct Node { val: i32, prev: Option, next: Option }
// List: 10 <-> 20 <-> 30
let mut head = Some(Box::new(Node { val: 10, prev: None, next: Some(Box::new(Node { val: 20, prev: None, next: Some(Box::new(Node { val: 30, prev: None, next: None })) })) }));
// Delete first node
if let Some(mut node) = head.take() {
head = node.next.take();
if let Some(ref mut new_head) = head {
new_head.prev = None;
}
}
// Print list
let mut current = &head;
while let Some(node) = current {
print!("{} -> ", node.val);
current = &node.next;
}
print!("null");
medium
A. null
B. 10 -> 20 -> 30 -> null
C. 20 -> 30 -> null
D. 30 -> null
Solution
Step 1: Initial list structure
The list starts as 10 <-> 20 <-> 30, with head at 10.
Step 2: Deletion of first node
Deleting first node moves head to 20, and sets 20.prev to None.
Step 3: Printing the list
Starting from new head (20), printing nodes gives 20 -> 30 -> null.
Final Answer:
20 -> 30 -> null -> Option C
Quick Check:
Head updated to second node, list prints from 20 [OK]
Hint: After deletion, head points to second node; print from there [OK]
Common Mistakes:
Printing old head after deletion
Not updating prev pointer causing broken links
Confusing next and prev pointers
4. Identify the error in this Rust code snippet that tries to delete the first node from a doubly linked list:
if head.is_some() {
head = head.unwrap().next;
if let Some(ref mut new_head) = head {
new_head.prev = None;
}
}
medium
A. Using unwrap() consumes head, causing a move error
B. Not setting new_head.prev to None
C. Missing check if head is None before deletion
D. Incorrectly updating tail pointer
Solution
Step 1: Understand unwrap() behavior on Option
Calling unwrap() on head moves the value out, consuming it and invalidating head.
Step 2: Consequence of move error
Assigning head = head.unwrap().next; causes a move error because head is used after being moved.
Final Answer:
Using unwrap() consumes head, causing a move error -> Option A
Quick Check:
unwrap() moves value, invalidating head [OK]
Hint: Avoid unwrap() on Option when reassigning; use take() [OK]
Common Mistakes:
Using unwrap() causing move errors
Not handling Option safely
Forgetting to update prev pointer
5. You have a doubly linked list with nodes: 5 <-> 15 <-> 25 <-> 35. After deleting the first node twice using correct Rust code, what will be the final list printed?
let mut head = Some(Box::new(Node { val: 5, prev: None, next: Some(Box::new(Node { val: 15, prev: None, next: Some(Box::new(Node { val: 25, prev: None, next: Some(Box::new(Node { val: 35, prev: None, next: None })) })) })) }));
// Delete first node twice
for _ in 0..2 {
if let Some(mut node) = head.take() {
head = node.next.take();
if let Some(ref mut new_head) = head {
new_head.prev = None;
}
}
}
// Print list
let mut current = &head;
while let Some(node) = current {
print!("{} -> ", node.val);
current = &node.next;
}
print!("null");
hard
A. 15 -> 25 -> 35 -> null
B. null
C. 35 -> null
D. 25 -> 35 -> null
Solution
Step 1: Initial list and first deletion
List starts as 5 <-> 15 <-> 25 <-> 35. First deletion removes 5, head moves to 15.
Step 2: Second deletion
Second deletion removes 15, head moves to 25, and 25.prev is set to None.