Challenge - 5 Problems
Doubly Linked List Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediateOutput of inserting nodes in a doubly linked list
What is the printed state of the doubly linked list after inserting nodes with values 10, 20, and 30 at the end?
DSA Rust
struct Node {
value: i32,
prev: Option<Box<Node>>,
next: Option<Box<Node>>,
}
struct DoublyLinkedList {
head: Option<Box<Node>>,
tail: Option<*mut Node>,
}
impl DoublyLinkedList {
fn new() -> Self {
DoublyLinkedList { head: None, tail: None }
}
fn append(&mut self, val: i32) {
let mut new_node = Box::new(Node { value: val, prev: None, next: None });
let raw_node: *mut _ = &mut *new_node;
match self.tail {
Some(tail_ptr) => unsafe {
(*tail_ptr).next = Some(new_node);
new_node.prev = Some(Box::from_raw(tail_ptr));
self.tail = Some(raw_node);
},
None => {
self.head = Some(new_node);
self.tail = Some(raw_node);
}
}
}
fn print_forward(&self) {
let mut current = self.head.as_ref();
while let Some(node) = current {
print!("{} <-> ", node.value);
current = node.next.as_ref();
}
println!("null");
}
}
fn main() {
let mut list = DoublyLinkedList::new();
list.append(10);
list.append(20);
list.append(30);
list.print_forward();
}Attempts:
2 left
💡 Hint
Think about how nodes are linked when appended at the end.
✗ Incorrect
Appending nodes adds them to the end, so the list prints in insertion order: 10, then 20, then 30.
❓ Predict Output
intermediateOutput after deleting the head node in a doubly linked list
Given a doubly linked list with nodes 5 <-> 15 <-> 25 <-> null, what is the printed state after deleting the head node?
DSA Rust
struct Node {
value: i32,
prev: Option<Box<Node>>,
next: Option<Box<Node>>,
}
struct DoublyLinkedList {
head: Option<Box<Node>>,
tail: Option<*mut Node>,
}
impl DoublyLinkedList {
fn new() -> Self {
DoublyLinkedList { head: None, tail: None }
}
fn append(&mut self, val: i32) {
let mut new_node = Box::new(Node { value: val, prev: None, next: None });
let raw_node: *mut _ = &mut *new_node;
match self.tail {
Some(tail_ptr) => unsafe {
(*tail_ptr).next = Some(new_node);
new_node.prev = Some(Box::from_raw(tail_ptr));
self.tail = Some(raw_node);
},
None => {
self.head = Some(new_node);
self.tail = Some(raw_node);
}
}
}
fn delete_head(&mut self) {
if let Some(mut old_head) = self.head.take() {
self.head = old_head.next.take();
if let Some(ref mut new_head) = self.head {
new_head.prev = None;
} else {
self.tail = None;
}
}
}
fn print_forward(&self) {
let mut current = self.head.as_ref();
while let Some(node) = current {
print!("{} <-> ", node.value);
current = node.next.as_ref();
}
println!("null");
}
}
fn main() {
let mut list = DoublyLinkedList::new();
list.append(5);
list.append(15);
list.append(25);
list.delete_head();
list.print_forward();
}Attempts:
2 left
💡 Hint
Deleting the head removes the first node and updates the head pointer.
✗ Incorrect
After deleting the head (5), the new head is 15, so the list is 15 <-> 25 <-> null.
🔧 Debug
advancedIdentify the bug in the doubly linked list append method
What error will occur when running this append method in the doubly linked list implementation?
DSA Rust
fn append(&mut self, val: i32) {
let mut new_node = Box::new(Node { value: val, prev: None, next: None });
match self.tail.take() {
Some(mut old_tail) => {
old_tail.next = Some(new_node);
new_node.prev = Some(old_tail);
self.tail = Some(new_node);
}
None => {
self.head = Some(new_node);
self.tail = self.head.clone();
}
}
}Attempts:
2 left
💡 Hint
Consider ownership and borrowing rules in Rust when moving variables.
✗ Incorrect
The 'old_tail' is moved when assigned to 'new_node.prev', so using it again to set 'old_tail.next' causes a compile-time error.
❓ Predict Output
advancedOutput after reversing a doubly linked list
Given a doubly linked list with nodes 1 <-> 2 <-> 3 <-> null, what is the printed state after reversing the list?
DSA Rust
struct Node {
value: i32,
prev: Option<Box<Node>>,
next: Option<Box<Node>>,
}
struct DoublyLinkedList {
head: Option<Box<Node>>,
tail: Option<*mut Node>,
}
impl DoublyLinkedList {
fn new() -> Self {
DoublyLinkedList { head: None, tail: None }
}
fn append(&mut self, val: i32) {
let mut new_node = Box::new(Node { value: val, prev: None, next: None });
let raw_node: *mut _ = &mut *new_node;
match self.tail {
Some(tail_ptr) => unsafe {
(*tail_ptr).next = Some(new_node);
new_node.prev = Some(Box::from_raw(tail_ptr));
self.tail = Some(raw_node);
},
None => {
self.head = Some(new_node);
self.tail = Some(raw_node);
}
}
}
fn reverse(&mut self) {
let mut current = self.head.take();
self.tail = current.as_ref().map(|node| &**node as *const Node as *mut Node);
let mut prev = None;
while let Some(mut node) = current {
let next = node.next.take();
node.next = prev;
if let Some(ref mut next_node) = node.next {
next_node.prev = Some(Box::new(Node {
value: node.value,
prev: None,
next: None,
}));
}
prev = Some(node);
current = next;
}
self.head = prev;
}
fn print_forward(&self) {
let mut current = self.head.as_ref();
while let Some(node) = current {
print!("{} <-> ", node.value);
current = node.next.as_ref();
}
println!("null");
}
}
fn main() {
let mut list = DoublyLinkedList::new();
list.append(1);
list.append(2);
list.append(3);
list.reverse();
list.print_forward();
}Attempts:
2 left
💡 Hint
Reversing swaps next and prev pointers for all nodes.
✗ Incorrect
Reversing the list changes the order to 3 <-> 2 <-> 1 <-> null.
🧠 Conceptual
expertMemory safety in doubly linked list node design in Rust
Which statement best explains why using Box for both prev and next pointers in a doubly linked list can cause problems in Rust?
Attempts:
2 left
💡 Hint
Think about ownership and cycles in Rust's memory model.
✗ Incorrect
Using Box for both prev and next creates strong ownership cycles, preventing memory from being freed, causing leaks.
