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 Doubly Linked List after Insertions
What is the printed state of the doubly linked list after inserting 10, 20, and 30 in order?
DSA Rust
struct Node {
data: 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, data: i32) {
let mut new_node = Box::new(Node { data, prev: None, next: None });
let raw_node: *mut _ = &mut *new_node;
match self.tail {
None => {
self.head = Some(new_node);
self.tail = Some(raw_node);
}
Some(tail) => unsafe {
(*tail).next = Some(new_node);
if let Some(ref mut next_node) = (*tail).next {
next_node.prev = Some(Box::from_raw(tail));
}
self.tail = Some(raw_node);
},
}
}
fn print_forward(&self) {
let mut current = self.head.as_ref();
while let Some(node) = current {
print!("{} -> ", node.data);
current = node.next.as_ref();
}
print!("null\n");
}
}
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 the order in which elements are appended to the list.
✗ Incorrect
The append method adds nodes at the end. So the list prints in the order 10, then 20, then 30.
❓ Predict Output
intermediateValue of head node after initialization
What is the value of the head node's data after creating a doubly linked list and inserting only one element 42?
DSA Rust
struct Node {
data: 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, data: i32) {
let mut new_node = Box::new(Node { data, prev: None, next: None });
let raw_node: *mut _ = &mut *new_node;
match self.tail {
None => {
self.head = Some(new_node);
self.tail = Some(raw_node);
}
Some(tail) => unsafe {
(*tail).next = Some(new_node);
if let Some(ref mut next_node) = (*tail).next {
next_node.prev = Some(Box::from_raw(tail));
}
self.tail = Some(raw_node);
},
}
}
}
fn main() {
let mut list = DoublyLinkedList::new();
list.append(42);
if let Some(ref head_node) = list.head {
println!("{}", head_node.data);
}
}Attempts:
2 left
💡 Hint
The first inserted node becomes the head.
✗ Incorrect
After inserting 42, the head node stores 42 as its data.
🔧 Debug
advancedIdentify the runtime error in doubly linked list append method
What runtime error will occur when running this append method in the doubly linked list implementation?
DSA Rust
fn append(&mut self, data: i32) {
let mut new_node = Box::new(Node { data, prev: None, next: None });
let raw_node: *mut _ = &mut *new_node;
match self.tail {
None => {
self.head = Some(new_node);
self.tail = Some(raw_node);
}
Some(tail) => unsafe {
(*tail).next = Some(new_node);
if let Some(ref mut next_node) = (*tail).next {
next_node.prev = Some(Box::from_raw(tail));
}
self.tail = Some(raw_node);
},
}
}Attempts:
2 left
💡 Hint
Look at how Box::from_raw is used on a pointer already owned elsewhere.
✗ Incorrect
Using Box::from_raw on a pointer that is still owned causes double free or use after free errors at runtime.
🧠 Conceptual
advancedWhy use Option> for prev and next in doubly linked list?
Why do we use Option> for the prev and next pointers in a doubly linked list node in Rust?
Attempts:
2 left
💡 Hint
Think about what happens at the start and end of the list.
✗ Incorrect
Option> allows prev and next to be None when there is no previous or next node, such as at the list ends.
🚀 Application
expertResulting list after mixed insertions and deletions
Given a doubly linked list initially empty, perform these operations in order: append 5, append 10, append 15, remove head, append 20. What is the final list printed forward?
DSA Rust
struct Node {
data: 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, data: i32) {
let mut new_node = Box::new(Node { data, prev: None, next: None });
let raw_node: *mut _ = &mut *new_node;
match self.tail {
None => {
self.head = Some(new_node);
self.tail = Some(raw_node);
}
Some(tail) => unsafe {
(*tail).next = Some(new_node);
self.tail = Some(raw_node);
},
}
}
fn remove_head(&mut self) {
if let Some(mut old_head) = self.head.take() {
self.head = old_head.next.take();
if self.head.is_none() {
self.tail = None;
}
}
}
fn print_forward(&self) {
let mut current = self.head.as_ref();
while let Some(node) = current {
print!("{} -> ", node.data);
current = node.next.as_ref();
}
print!("null\n");
}
}
fn main() {
let mut list = DoublyLinkedList::new();
list.append(5);
list.append(10);
list.append(15);
list.remove_head();
list.append(20);
list.print_forward();
}Attempts:
2 left
💡 Hint
Removing head removes the first element, then appending adds at the end.
✗ Incorrect
After removing head (5), the list starts at 10, then 15, then appending 20 adds at the end.
