Skip to content

Commit 8843654

Browse files
authored
Merge pull request #82 from NSS-Workshops/linked-list-updates
cleaned up updated linked list module
2 parents a93fc19 + 946eacb commit 8843654

22 files changed

Lines changed: 68 additions & 1067 deletions

File tree

src/sections/06-linked-lists/02-linked-lists-intro/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ Jordan pulled out a piece of paper and started sketching. "I've been reading abo
7171
They drew a simple diagram:
7272

7373
```
74-
🎵 "Bohemian Rhapsody" → 🎵 "Hotel California" → 🎵 "Stairway to Heaven" → 🎵 "Sweet Child O' Mine" → 🎵 "Imagine" → null
74+
<start> → 🎵 "Bohemian Rhapsody" → 🎵 "Hotel California" → 🎵 "Stairway to Heaven" → 🎵 "Sweet Child O' Mine" → 🎵 "Imagine" → null
7575
```
7676

7777
"See?" Jordan continued excitedly. "Each song is connected to the next song, like links in a chain. If I want to add 'Thunderstruck' after 'Hotel California', I just need to:"

src/sections/06-linked-lists/02-linked-lists-intro/solution.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class SongNode {
77
}
88

99
toString() {
10-
return \`\${this.title} - \${this.artist}\`;
10+
return `${this.title} - ${this.artist}`;
1111
}
1212
}
1313

@@ -47,7 +47,7 @@ function playNextSong(playlist, targetSong) {
4747
function removeSong(playlist, targetTitle) {
4848
// Handle case where first song should be removed
4949
if (playlist && playlist.title === targetTitle) {
50-
console.log(\`🗑️ Removed first song: \${playlist.toString()}\`);
50+
console.log(`🗑️ Removed first song: ${playlist.toString()}`);
5151
return playlist.next;
5252
}
5353

@@ -57,13 +57,13 @@ function removeSong(playlist, targetTitle) {
5757
if (currentSong.next.title === targetTitle) {
5858
const removedSong = currentSong.next;
5959
currentSong.next = removedSong.next;
60-
console.log(\`🗑️ Removed song: \${removedSong.toString()}\`);
60+
console.log(`🗑️ Removed song: ${removedSong.toString()}`);
6161
return playlist;
6262
}
6363
currentSong = currentSong.next;
6464
}
6565

66-
console.log(\`🎵 Song "\${targetTitle}" not found in playlist\`);
66+
console.log(`🎵 Song "${targetTitle}" not found in playlist`);
6767
return playlist;
6868
}
6969

@@ -76,6 +76,6 @@ function countSongs(playlist) {
7676
currentSong = currentSong.next;
7777
}
7878

79-
console.log(\`📊 Total songs in playlist: \${count}\`);
79+
console.log(`📊 Total songs in playlist: ${count}`);
8080
return count;
8181
}

src/sections/06-linked-lists/03-linked-list-types/checkpoint.jsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ export default [
1212
"🚫 Circular linked lists cannot be traversed",
1313
"📈 Doubly linked lists require more memory than singly linked lists"
1414
],
15-
correctAnswers: [0,1,2],
16-
// explanation: {
17-
// "⟷ Doubly linked lists enable bidirectional navigation": "✅ Correct — Doubly linked lists have both next and prev pointers.",
18-
// "🔄 Circular linked lists create infinite loops": "✅ Correct — Circular lists loop back to the beginning.",
19-
// "💾 Singly linked lists use less memory per node": "✅ Correct — Singly linked lists only need one pointer per node.",
20-
// "⚡ All linked list types have the same performance characteristics": "❌ Incorrect — Different types have different performance characteristics.",
21-
// "🚫 Circular linked lists cannot be traversed": "❌ Incorrect — Circular lists can be traversed with proper loop detection.",
22-
// "📈 Doubly linked lists require more memory than singly linked lists": "✅ Correct — Two pointers per node vs one."
23-
// }
15+
correctAnswers: [0,1,2,5],
16+
explanation:
17+
(<ul>
18+
<li>⟷ Doubly linked lists enable bidirectional navigation — ✅ Correct: Doubly linked lists have both <code>next</code> and <code>prev</code> pointers.</li>
19+
<li>🔄 Circular linked lists create infinite loops — ✅ Correct: Circular lists loop back to the beginning.</li>
20+
<li>💾 Singly linked lists use less memory per node — ✅ Correct: Singly linked lists only need one pointer per node.</li>
21+
<li>⚡ All linked list types have the same performance characteristics — ❌ Incorrect: Different types have different performance characteristics.</li>
22+
<li>🚫 Circular linked lists cannot be traversed — ❌ Incorrect: Circular lists can be traversed with proper loop detection.</li>
23+
<li>📈 Doubly linked lists require more memory than singly linked lists — ✅ Correct: Two pointers per node vs one.</li>
24+
</ul>)
2425
},
2526
{
2627
type: QUESTION_TYPES.TEXT,

src/sections/06-linked-lists/03-linked-list-types/index.md

Lines changed: 1 addition & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -333,66 +333,6 @@ class SmartCircularPlaylist extends CircularPlaylist {
333333
}
334334
```
335335

336-
## Real-World Applications of Different List Types
337-
338-
Maya used the whiteboard to show how different linked list types solve different real-world problems:
339-
340-
### Singly Linked Lists
341-
- **Music streaming**: Basic playlist playback
342-
- **Browser history**: Forward navigation only
343-
- **Undo systems**: Simple action history
344-
- **RSS feeds**: Chronological article lists
345-
346-
### Doubly Linked Lists
347-
- **Media players**: Forward and backward navigation
348-
- **Text editors**: Cursor movement in documents
349-
- **Browser tabs**: Navigate between open tabs
350-
- **Photo galleries**: Previous/next image viewing
351-
352-
### Circular Linked Lists
353-
- **Round-robin scheduling**: CPU task scheduling
354-
- **Multiplayer games**: Turn-based player rotation
355-
- **Carousel displays**: Infinite image rotation
356-
- **Background music**: Continuous playlist looping
357-
358-
## ⏱️ Alex's Circular Playlist Challenge!
359-
360-
"Now for the advanced challenge," Maya said with a smile. "Jordan wants to implement a feature that can detect if a playlist has accidentally become circular when it shouldn't be."
361-
362-
Jordan explained: "Sometimes when building playlists programmatically, you might accidentally create a loop. We need a way to detect this."
363-
364-
<iframe width="560" height="315" src="https://www.youtube.com/embed/S5TcPmTl6ww?si=82xnZM_NhIV7CVqH" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
365-
366-
🔓 **Uncomment the below code section in the editor 👉:**
367-
- Implement `detectLoop()` to check if a playlist has an unintended circular connection
368-
- Use the "tortoise and hare" algorithm (two pointers at different speeds)
369-
- **Click Run Code**
370-
- **Inspect 📋 Console Output window and run test to check for correctness!**
371-
372-
"This challenge teaches you about cycle detection - a classic computer science problem," Maya explained.
373-
374-
## Choosing the Right Playlist Type
375-
376-
As their session continued, Maya helped Alex and Jordan understand when to use each type:
377-
378-
### Use Singly Linked Lists When:
379-
- **Memory is limited**: Only one pointer per node
380-
- **Simple forward navigation**: No need to go backward
381-
- **Implementation simplicity**: Easier to code and debug
382-
- **Append-heavy operations**: Frequently adding to the end
383-
384-
### Use Doubly Linked Lists When:
385-
- **Bidirectional navigation**: Need to move forward and backward
386-
- **Frequent deletions**: Easier to remove nodes when you have previous pointer
387-
- **LRU caches**: Need to move items to front/back efficiently
388-
- **Text editing**: Cursor can move in both directions
389-
390-
### Use Circular Linked Lists When:
391-
- **Continuous cycling**: Round-robin or infinite loops needed
392-
- **No clear start/end**: Data naturally forms a cycle
393-
- **Resource sharing**: CPU scheduling, printer queues
394-
- **Game mechanics**: Turn-based systems, circular menus
395-
396336
## Performance Comparison
397337

398338
Jordan had prepared a comparison table:
@@ -407,38 +347,4 @@ Jordan had prepared a comparison table:
407347
| **Delete node** | O(n) to find prev | O(1) if have node | O(n) to find prev |
408348
| **Cycle detection** | Not applicable | Not applicable | Built-in |
409349

410-
*With tail pointer
411-
412-
## Looking Ahead: Advanced Playlist Features
413-
414-
As their session wound down, Jordan was already thinking about even more advanced features:
415-
416-
"What if we combined these concepts? Like a doubly linked circular playlist for a DJ system where you can go forward, backward, and it loops forever?"
417-
418-
Maya's eyes twinkled. "That's absolutely possible! You could create a doubly circular linked list. Each node would have both next and previous pointers, and the first and last nodes would connect to each other."
419-
420-
Alex was amazed. "So you can mix and match these concepts?"
421-
422-
"Exactly," Maya said. "Data structures are tools, and like any tools, you can combine them creatively to solve complex problems."
423-
424-
## Key Insights from Playlist Types
425-
426-
By the end of their session, Alex had learned:
427-
428-
- **Singly linked lists** provide simple, memory-efficient forward navigation
429-
- **Doubly linked lists** enable bidirectional navigation at the cost of more memory
430-
- **Circular linked lists** create infinite loops perfect for continuous operations
431-
- **Each type solves different problems** and has different trade-offs
432-
- **Real-world applications** exist for all three types
433-
- **Performance characteristics** vary significantly between types
434-
- **Creative combinations** are possible for complex requirements
435-
436-
Jordan was already sketching ideas for their next features. "I want to build a smart DJ system that can seamlessly switch between different playlist types based on the situation!"
437-
438-
"That sounds like an excellent project," Maya said. "Understanding these fundamental variations gives you the building blocks to create sophisticated systems."
439-
440-
As they packed up, Alex reflected on how much their understanding had grown. "It's amazing how something as simple as changing the connections between nodes can create completely different behaviors."
441-
442-
Maya smiled. "That's the beauty of data structures, Alex. Small changes in structure can lead to dramatically different capabilities. Tomorrow, we'll explore how to traverse and manipulate these different playlist types efficiently."
443-
444-
The journey into linked list variations had opened up a world of possibilities, each type offering unique advantages for different musical and programming challenges.
350+
*With tail pointer

src/sections/06-linked-lists/03-linked-list-types/solution.js

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -55,27 +55,6 @@ function navigatePlaylist(currentSong, direction, steps = 1) {
5555
return current;
5656
}
5757

58-
function detectLoop(playlist) {
59-
// Floyd's cycle detection algorithm (tortoise and hare)
60-
if (!playlist) return false;
61-
62-
let slow = playlist;
63-
let fast = playlist;
64-
65-
while (fast && fast.next) {
66-
slow = slow.next; // Move one step
67-
fast = fast.next.next; // Move two steps
68-
69-
if (slow === fast) {
70-
console.log("🔄 Loop detected in playlist!");
71-
return true;
72-
}
73-
}
74-
75-
console.log("✅ No loop detected - playlist is linear");
76-
return false;
77-
}
78-
7958
// Helper function to create a test circular playlist
8059
function createCircularPlaylist() {
8160
const songA = new DoublySongNode("Song A", "Artist A");
@@ -93,9 +72,4 @@ function createCircularPlaylist() {
9372
console.log("=== Testing navigatePlaylist ===");
9473
console.log("Forward 1 step from Hotel California:", navigatePlaylist(song2, "forward", 1)?.title);
9574
console.log("Backward 1 step from Stairway to Heaven:", navigatePlaylist(song3, "backward", 1)?.title);
96-
console.log("Forward 2 steps from Bohemian Rhapsody:", navigatePlaylist(song1, "forward", 2)?.title);
97-
98-
console.log("\n=== Testing detectLoop ===");
99-
console.log("Linear playlist has loop:", detectLoop(song1));
100-
const circularPlaylist = createCircularPlaylist();
101-
console.log("Circular playlist has loop:", detectLoop(circularPlaylist));
75+
console.log("Forward 2 steps from Bohemian Rhapsody:", navigatePlaylist(song1, "forward", 2)?.title);

src/sections/06-linked-lists/03-linked-list-types/starterCode.js

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -46,27 +46,6 @@ function navigatePlaylist(currentSong, direction, steps = 1) {
4646
}
4747
*/
4848

49-
// ⏱️ Alex's Circular Playlist Challenge!
50-
// 🔓 Uncomment the below code section and implement the required logic:
51-
52-
/*
53-
function detectLoop(playlist) {
54-
// Detect if a playlist has a circular connection (Floyd's cycle detection)
55-
// Return true if loop exists, false otherwise
56-
57-
if (!playlist) return false;
58-
59-
let slow = playlist;
60-
let fast = playlist;
61-
62-
// TODO: Implement the tortoise and hare algorithm
63-
// Hint: Move slow pointer one step, fast pointer two steps
64-
// If they meet, there's a loop
65-
66-
return false;
67-
}
68-
*/
69-
7049
// Helper function to create a test circular playlist
7150
function createCircularPlaylist() {
7251
const songA = new DoublySongNode("Song A", "Artist A");
@@ -86,9 +65,4 @@ console.log("=== Testing navigatePlaylist ===");
8665
console.log("Forward 1 step from Hotel California:", navigatePlaylist(song2, "forward", 1)?.title);
8766
console.log("Backward 1 step from Stairway to Heaven:", navigatePlaylist(song3, "backward", 1)?.title);
8867
console.log("Forward 2 steps from Bohemian Rhapsody:", navigatePlaylist(song1, "forward", 2)?.title);
89-
90-
console.log("\n=== Testing detectLoop ===");
91-
console.log("Linear playlist has loop:", detectLoop(song1));
92-
const circularPlaylist = createCircularPlaylist();
93-
console.log("Circular playlist has loop:", detectLoop(circularPlaylist));
9468
*/

src/sections/06-linked-lists/03-linked-list-types/tests.js

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -99,48 +99,7 @@ const tests = [
9999
}
100100
},
101101
message: "navigatePlaylist should handle forward, backward, and multi-step navigation."
102-
},
103-
{
104-
name: "Test detectLoop function",
105-
test: (code) => {
106-
try {
107-
const testCode = code + `
108-
let linearResult = false;
109-
let circularResult = false;
110-
111-
if (typeof detectLoop === 'function') {
112-
// Test with linear playlist
113-
linearResult = detectLoop(song1);
114-
115-
// Test with circular playlist
116-
const circularPlaylist = createCircularPlaylist();
117-
circularResult = detectLoop(circularPlaylist);
118-
}
119-
120-
return ({ linearResult, circularResult });
121-
`;
122-
123-
const testResult = new Function(testCode)();
124-
125-
if (typeof testResult.linearResult === 'undefined') {
126-
return new TestResult({ passed: false, message: "detectLoop function not found. Make sure to uncomment and implement it." });
127-
}
128-
129-
if (testResult.linearResult !== false) {
130-
return new TestResult({ passed: false, message: "detectLoop should return false for linear playlists" });
131-
}
132-
133-
if (testResult.circularResult !== true) {
134-
return new TestResult({ passed: false, message: "detectLoop should return true for circular playlists" });
135-
}
136-
137-
return new TestResult({ passed: true });
138-
} catch (error) {
139-
return new TestResult({ passed: false, message: error.message });
140-
}
141-
},
142-
message: "detectLoop should correctly identify circular vs linear playlists using Floyd's algorithm."
143-
},
102+
}
144103
];
145104

146105
export { tests, TestResult };

src/sections/06-linked-lists/04-linked-list-tradeoffs/checkpoint.jsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@ export default [
1010
"Arrays require shifting elements for middle insertions",
1111
"Linked lists provide O(1) random access",
1212
"Arrays and linked lists have identical performance",
13-
"Linked lists use less memory than arrays"
1413
],
1514
correctAnswers: [0,1,2],
16-
// explanation: {
17-
// "Arrays provide O(1) random access": "✅ Correct — Arrays can access any element by index in O(1) time.",
18-
// "Linked lists provide O(1) insertion at beginning": "✅ Correct — Just update head pointer in O(1) time.",
19-
// "Arrays require shifting elements for middle insertions": "✅ Correct — Elements after insertion point must shift.",
20-
// "Linked lists provide O(1) random access": "❌ Incorrect — Must traverse from head, O(n) time.",
21-
// "Arrays and linked lists have identical performance": "❌ Incorrect — They have different strengths and weaknesses.",
22-
// "Linked lists use less memory than arrays": "❌ Incorrect — Extra pointers increase memory usage."
23-
// }
15+
explanation: (
16+
<ul>
17+
<li>Arrays provide O(1) random access — ✅ Correct: Arrays can access any element by index in O(1) time.</li>
18+
<li>Linked lists provide O(1) insertion at beginning — ✅ Correct: Just update the head pointer in O(1) time.</li>
19+
<li>Arrays require shifting elements for middle insertions — ✅ Correct: Elements after the insertion point must shift.</li>
20+
<li>Linked lists provide O(1) random access — ❌ Incorrect: You must traverse from the head, which takes O(n) time.</li>
21+
<li>Arrays and linked lists have identical performance — ❌ Incorrect: They have different strengths and weaknesses.</li>
22+
</ul>
23+
)
2424
},
2525
{
2626
type: QUESTION_TYPES.TEXT,
2727
questionJsx: "What is the time complexity for accessing the 50th element in a linked list?",
2828
correctAnswer: "O(n)",
29-
// explanation: "Accessing the 50th element requires traversing from the head through 49 nodes, making it **O(n)** time complexity, where n is the position of the element."
29+
explanation: ("Accessing the 50th element requires traversing from the head through 49 nodes, making it **O(n)** time complexity, where n is the position of the element.")
3030
}
3131
]
Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
import contentMd from './index.md?raw';
2-
import starterCode from './starterCode.js?raw';
3-
import solution from './solution.js?raw';
4-
import { tests } from './tests.js';
52
import questions from './checkpoint.jsx';
63
import { Checkpoint } from '@nss-workshops/nss-core';
74

@@ -11,10 +8,5 @@ export default {
118
previousChapterId: "linked-types",
129
nextChapterId: "linked-traversal",
1310
content: contentMd,
14-
exercises: [{
15-
starterCode,
16-
solution,
17-
tests
18-
}],
1911
quiz: {component: () => <Checkpoint questions={questions}/> }
2012
};

src/sections/06-linked-lists/04-linked-list-tradeoffs/index.md

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -176,17 +176,4 @@ Inserting at beginning:
176176
177177
new head
178178
Just change two pointers! O(1)
179-
```
180-
181-
## ⏱️ Alex's Performance Analysis Challenge!
182-
183-
Maya pulled out her tablet. "Alex, let's put this theory to the test. I want you to implement a function that compares the performance characteristics of both approaches."
184-
185-
Jordan nodded enthusiastically. "This would help me understand exactly when to use each approach!"
186-
187-
🔓 **Uncomment the below code section in the editor 👉:**
188-
- Implement `comparePerformance()` to fill in different operations time complexity in big O notation
189-
- **Click Run Code**
190-
- **Inspect 📋 Console Output window and run test to check for correctness!**
191-
192-
"This challenge will help you understand the practical implications of these performance differences," Maya explained.
179+
```

0 commit comments

Comments
 (0)