📖 Scenario: Imagine you have a chain of connected train cars. Sometimes, the last car connects back to an earlier car, making a loop. We want to check if the train cars form such a loop or if the chain ends normally.
🎯 Goal: Build a simple linked list in Rust and write code to check if the list is circular (has a loop) or not.
📋 What You'll Learn
Create a linked list with exactly 4 nodes with values 10, 20, 30, and 40
Add a boolean variable called make_circular to decide if the list should loop back
Write a function called is_circular that returns true if the list has a loop, otherwise false
Print the result of is_circular for the created list
💡 Why This Matters
🌍 Real World
Circular linked lists are used in real-world applications like music playlists, task scheduling, and multiplayer games where the sequence repeats.
💼 Career
Understanding how to detect loops in linked lists is important for software engineers working on data structures, memory management, and debugging complex pointer-based code.
Progress0 / 4 steps
1
Create a linked list with 4 nodes
Create a linked list with 4 nodes having values 10, 20, 30, and 40. Use a struct called Node with fields value: i32 and next: Option>. Create a variable called head pointing to the first node.
DSA Rust
Hint
Define the Node struct first. Then create nodes from last to first, linking each with next: Some(Box::new(...)).
2
Add a boolean to control circular linking
Add a boolean variable called make_circular and set it to true. This will decide if the last node links back to the head node to form a loop.
DSA Rust
Hint
Just add let make_circular = true; inside main.
3
Write a function to detect if the list is circular
Write a function called is_circular that takes a reference to a Node and returns true if the list has a loop, otherwise false. Use two pointers called slow and fast to move through the list. If they meet, return true. If fast or fast.next is None, return false.
DSA Rust
Hint
Use two pointers moving at different speeds. If they meet, the list is circular.
4
Make the list circular if requested and print the result
If make_circular is true, link the last node's next to the head to form a loop. Then call is_circular(&head) and print the result using println!("{}", result).
DSA Rust
Hint
To form a loop, link the last node's next to the head. Then call is_circular(&head) and print the result.
Practice
(1/5)
1. What does it mean if a linked list is circular?
easy
A. The linked list has no nodes
B. The linked list contains only one node
C. The linked list nodes are sorted in ascending order
D. The last node points back to one of the previous nodes, forming a loop
Solution
Step 1: Understand linked list structure
A linked list is a chain of nodes where each node points to the next node.
Step 2: Define circular linked list
If the last node points back to any previous node, it creates a loop, making the list circular.
Final Answer:
The last node points back to one of the previous nodes, forming a loop -> Option D
Quick Check:
Circular linked list = last node points back [OK]
Hint: Circular means last node links back to earlier node [OK]
Common Mistakes:
Thinking circular means sorted
Confusing empty list with circular
Assuming single node list is always circular
2. Which Rust code snippet correctly defines a singly linked list node struct?
easy
A. struct Node { value: i32, next: Option }
B. struct Node { value: i32, next: Node }
C. struct Node { value: i32, next: &Node }
D. struct Node { value: i32, next: Box<Node> }
Solution
Step 1: Understand Rust ownership for linked lists
Rust requires using Option for next to allow nullable and heap allocation.
Step 2: Check each option
struct Node { value: i32, next: Option } uses Option, which is correct. Others either lack Option or use references incorrectly.
Using raw Node type for next causes infinite size error
Using references without lifetimes
Omitting Option for nullable next
3. Given the following Rust code to detect a circular linked list, what will be printed?
fn is_circular(head: &Option) -> bool {
let mut slow = head.as_ref();
let mut fast = head.as_ref();
while let (Some(s), Some(f)) = (slow, fast) {
fast = f.next.as_ref().and_then(|n| n.next.as_ref());
slow = s.next.as_ref();
if slow == fast {
return true;
}
}
false
}
// List: 1 -> 2 -> 3 -> 2 (loop back to node with value 2)
// Calling is_circular returns what?
medium
A. false
B. true
C. Compilation error
D. Infinite loop
Solution
Step 1: Understand Floyd's cycle detection
Two pointers move at different speeds; if they meet, list is circular.
Step 2: Analyze given list and code
List loops back from node 3 to node 2, so slow and fast pointers will meet, returning true.
Final Answer:
true -> Option B
Quick Check:
Floyd's algorithm detects loop = true [OK]
Hint: Floyd's cycle detection returns true if pointers meet [OK]
Common Mistakes:
Confusing pointer movement speeds
Not checking both pointers for null
Assuming no loop when pointers meet
4. Identify the bug in this Rust function that tries to detect a circular linked list:
fn has_cycle(head: &Option) -> bool {
let mut slow = head.as_ref();
let mut fast = head.as_ref();
while fast.is_some() && fast.unwrap().next.is_some() {
slow = slow.unwrap().next.as_ref();
fast = fast.unwrap().next.as_ref().unwrap().next.as_ref();
if slow == fast {
return true;
}
}
false
}
medium
A. Function always returns false due to wrong loop condition
B. Pointers move at the same speed, so no cycle detection
C. Using unwrap() without checking can cause panic if null
D. Missing return type causes compilation error
Solution
Step 1: Check unwrap usage safety
Using unwrap() without confirming Some can panic if null is encountered.
Step 2: Identify risk in loop
fast.unwrap().next.as_ref().unwrap() assumes next exists, which may not be true at list end.
Final Answer:
Using unwrap() without checking can cause panic if null -> Option C
Quick Check:
Unsafe unwrap causes panic [OK]
Hint: Avoid unwrap without checking Option first [OK]
Common Mistakes:
Ignoring unwrap panic risk
Assuming pointers move same speed
Not checking loop exit conditions
5. You have a linked list where the last node's next pointer is mistakenly set to itself, creating a single-node loop. How should you modify the Rust cycle detection function to correctly detect this case?
hard
A. Use a hash set to store visited nodes and detect repeats
B. Ignore cases where next points to itself, treat as non-circular
C. Only check if fast pointer reaches null to decide no cycle
D. Check if slow and fast pointers meet even if they start at the same node
Solution
Step 1: Understand single-node loop problem
If a node points to itself, Floyd's algorithm may detect cycle, but edge cases can be tricky.
Step 2: Use hash set for robust detection
Storing visited nodes in a hash set helps detect any repeated node, including self-loop cases.
Final Answer:
Use a hash set to store visited nodes and detect repeats -> Option A
Quick Check:
Hash set detects all cycles including self-loops [OK]
Hint: Use hash set to catch all loops including self-pointing nodes [OK]
Common Mistakes:
Assuming Floyd's algorithm covers all edge cases
Ignoring self-loop as cycle
Not handling single-node circular lists
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.