From 946eacba550beef78ca9999ab7bac34effcfd7ce Mon Sep 17 00:00:00 2001 From: Gabe Cziprusz Date: Mon, 23 Feb 2026 13:14:37 -0600 Subject: [PATCH] cleaned up updated linked list module --- .../02-linked-lists-intro/index.md | 2 +- .../02-linked-lists-intro/solution.js | 10 +- .../03-linked-list-types/checkpoint.jsx | 19 +- .../03-linked-list-types/index.md | 96 +--------- .../03-linked-list-types/solution.js | 28 +-- .../03-linked-list-types/starterCode.js | 26 --- .../03-linked-list-types/tests.js | 43 +---- .../04-linked-list-tradeoffs/checkpoint.jsx | 20 +-- .../04-linked-list-tradeoffs/index.jsx | 8 - .../04-linked-list-tradeoffs/index.md | 15 +- .../04-linked-list-tradeoffs/solution.js | 111 ------------ .../04-linked-list-tradeoffs/starterCode.js | 106 ----------- .../04-linked-list-tradeoffs/tests.js | 101 ----------- .../05-node-based-traversal/index.md | 124 +------------ .../05-node-based-traversal/solution.js | 92 +--------- .../05-node-based-traversal/starterCode.js | 79 --------- .../05-node-based-traversal/tests.js | 167 ++---------------- .../06-linked-lists/06-info-sheet/index.md | 1 - .../07-supplemental-materials/index.md | 2 - .../06-linked-lists/08-glossary/index.jsx | 3 - .../09-checkpoint/checkpoint.jsx | 49 +++-- .../06-linked-lists/_b4f7e9a2/index.jsx | 33 +--- 22 files changed, 68 insertions(+), 1067 deletions(-) delete mode 100644 src/sections/06-linked-lists/04-linked-list-tradeoffs/solution.js delete mode 100644 src/sections/06-linked-lists/04-linked-list-tradeoffs/starterCode.js delete mode 100644 src/sections/06-linked-lists/04-linked-list-tradeoffs/tests.js diff --git a/src/sections/06-linked-lists/02-linked-lists-intro/index.md b/src/sections/06-linked-lists/02-linked-lists-intro/index.md index 1a11910..cca5a34 100644 --- a/src/sections/06-linked-lists/02-linked-lists-intro/index.md +++ b/src/sections/06-linked-lists/02-linked-lists-intro/index.md @@ -71,7 +71,7 @@ Jordan pulled out a piece of paper and started sketching. "I've been reading abo They drew a simple diagram: ``` -šŸŽµ "Bohemian Rhapsody" → šŸŽµ "Hotel California" → šŸŽµ "Stairway to Heaven" → šŸŽµ "Sweet Child O' Mine" → šŸŽµ "Imagine" → null + → šŸŽµ "Bohemian Rhapsody" → šŸŽµ "Hotel California" → šŸŽµ "Stairway to Heaven" → šŸŽµ "Sweet Child O' Mine" → šŸŽµ "Imagine" → null ``` "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:" diff --git a/src/sections/06-linked-lists/02-linked-lists-intro/solution.js b/src/sections/06-linked-lists/02-linked-lists-intro/solution.js index a3c308d..23cd75d 100644 --- a/src/sections/06-linked-lists/02-linked-lists-intro/solution.js +++ b/src/sections/06-linked-lists/02-linked-lists-intro/solution.js @@ -7,7 +7,7 @@ class SongNode { } toString() { - return \`\${this.title} - \${this.artist}\`; + return `${this.title} - ${this.artist}`; } } @@ -47,7 +47,7 @@ function playNextSong(playlist, targetSong) { function removeSong(playlist, targetTitle) { // Handle case where first song should be removed if (playlist && playlist.title === targetTitle) { - console.log(\`šŸ—‘ļø Removed first song: \${playlist.toString()}\`); + console.log(`šŸ—‘ļø Removed first song: ${playlist.toString()}`); return playlist.next; } @@ -57,13 +57,13 @@ function removeSong(playlist, targetTitle) { if (currentSong.next.title === targetTitle) { const removedSong = currentSong.next; currentSong.next = removedSong.next; - console.log(\`šŸ—‘ļø Removed song: \${removedSong.toString()}\`); + console.log(`šŸ—‘ļø Removed song: ${removedSong.toString()}`); return playlist; } currentSong = currentSong.next; } - console.log(\`šŸŽµ Song "\${targetTitle}" not found in playlist\`); + console.log(`šŸŽµ Song "${targetTitle}" not found in playlist`); return playlist; } @@ -76,6 +76,6 @@ function countSongs(playlist) { currentSong = currentSong.next; } - console.log(\`šŸ“Š Total songs in playlist: \${count}\`); + console.log(`šŸ“Š Total songs in playlist: ${count}`); return count; } \ No newline at end of file diff --git a/src/sections/06-linked-lists/03-linked-list-types/checkpoint.jsx b/src/sections/06-linked-lists/03-linked-list-types/checkpoint.jsx index f75b8de..ba91804 100644 --- a/src/sections/06-linked-lists/03-linked-list-types/checkpoint.jsx +++ b/src/sections/06-linked-lists/03-linked-list-types/checkpoint.jsx @@ -12,15 +12,16 @@ export default [ "🚫 Circular linked lists cannot be traversed", "šŸ“ˆ Doubly linked lists require more memory than singly linked lists" ], - correctAnswers: [0,1,2], - // explanation: { - // "⟷ Doubly linked lists enable bidirectional navigation": "āœ… Correct — Doubly linked lists have both next and prev pointers.", - // "šŸ”„ Circular linked lists create infinite loops": "āœ… Correct — Circular lists loop back to the beginning.", - // "šŸ’¾ Singly linked lists use less memory per node": "āœ… Correct — Singly linked lists only need one pointer per node.", - // "⚔ All linked list types have the same performance characteristics": "āŒ Incorrect — Different types have different performance characteristics.", - // "🚫 Circular linked lists cannot be traversed": "āŒ Incorrect — Circular lists can be traversed with proper loop detection.", - // "šŸ“ˆ Doubly linked lists require more memory than singly linked lists": "āœ… Correct — Two pointers per node vs one." - // } + correctAnswers: [0,1,2,5], + explanation: + () }, { type: QUESTION_TYPES.TEXT, diff --git a/src/sections/06-linked-lists/03-linked-list-types/index.md b/src/sections/06-linked-lists/03-linked-list-types/index.md index 05c7983..93d5415 100644 --- a/src/sections/06-linked-lists/03-linked-list-types/index.md +++ b/src/sections/06-linked-lists/03-linked-list-types/index.md @@ -333,66 +333,6 @@ class SmartCircularPlaylist extends CircularPlaylist { } ``` -## Real-World Applications of Different List Types - -Maya used the whiteboard to show how different linked list types solve different real-world problems: - -### Singly Linked Lists -- **Music streaming**: Basic playlist playback -- **Browser history**: Forward navigation only -- **Undo systems**: Simple action history -- **RSS feeds**: Chronological article lists - -### Doubly Linked Lists -- **Media players**: Forward and backward navigation -- **Text editors**: Cursor movement in documents -- **Browser tabs**: Navigate between open tabs -- **Photo galleries**: Previous/next image viewing - -### Circular Linked Lists -- **Round-robin scheduling**: CPU task scheduling -- **Multiplayer games**: Turn-based player rotation -- **Carousel displays**: Infinite image rotation -- **Background music**: Continuous playlist looping - -## ā±ļø Alex's Circular Playlist Challenge! - -"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." - -Jordan explained: "Sometimes when building playlists programmatically, you might accidentally create a loop. We need a way to detect this." - - - -šŸ”“ **Uncomment the below code section in the editor šŸ‘‰:** -- Implement `detectLoop()` to check if a playlist has an unintended circular connection -- Use the "tortoise and hare" algorithm (two pointers at different speeds) -- **Click Run Code** -- **Inspect šŸ“‹ Console Output window and run test to check for correctness!** - -"This challenge teaches you about cycle detection - a classic computer science problem," Maya explained. - -## Choosing the Right Playlist Type - -As their session continued, Maya helped Alex and Jordan understand when to use each type: - -### Use Singly Linked Lists When: -- **Memory is limited**: Only one pointer per node -- **Simple forward navigation**: No need to go backward -- **Implementation simplicity**: Easier to code and debug -- **Append-heavy operations**: Frequently adding to the end - -### Use Doubly Linked Lists When: -- **Bidirectional navigation**: Need to move forward and backward -- **Frequent deletions**: Easier to remove nodes when you have previous pointer -- **LRU caches**: Need to move items to front/back efficiently -- **Text editing**: Cursor can move in both directions - -### Use Circular Linked Lists When: -- **Continuous cycling**: Round-robin or infinite loops needed -- **No clear start/end**: Data naturally forms a cycle -- **Resource sharing**: CPU scheduling, printer queues -- **Game mechanics**: Turn-based systems, circular menus - ## Performance Comparison Jordan had prepared a comparison table: @@ -407,38 +347,4 @@ Jordan had prepared a comparison table: | **Delete node** | O(n) to find prev | O(1) if have node | O(n) to find prev | | **Cycle detection** | Not applicable | Not applicable | Built-in | -*With tail pointer - -## Looking Ahead: Advanced Playlist Features - -As their session wound down, Jordan was already thinking about even more advanced features: - -"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?" - -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." - -Alex was amazed. "So you can mix and match these concepts?" - -"Exactly," Maya said. "Data structures are tools, and like any tools, you can combine them creatively to solve complex problems." - -## Key Insights from Playlist Types - -By the end of their session, Alex had learned: - -- **Singly linked lists** provide simple, memory-efficient forward navigation -- **Doubly linked lists** enable bidirectional navigation at the cost of more memory -- **Circular linked lists** create infinite loops perfect for continuous operations -- **Each type solves different problems** and has different trade-offs -- **Real-world applications** exist for all three types -- **Performance characteristics** vary significantly between types -- **Creative combinations** are possible for complex requirements - -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!" - -"That sounds like an excellent project," Maya said. "Understanding these fundamental variations gives you the building blocks to create sophisticated systems." - -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." - -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." - -The journey into linked list variations had opened up a world of possibilities, each type offering unique advantages for different musical and programming challenges. \ No newline at end of file +*With tail pointer \ No newline at end of file diff --git a/src/sections/06-linked-lists/03-linked-list-types/solution.js b/src/sections/06-linked-lists/03-linked-list-types/solution.js index 126e675..02446fb 100644 --- a/src/sections/06-linked-lists/03-linked-list-types/solution.js +++ b/src/sections/06-linked-lists/03-linked-list-types/solution.js @@ -55,27 +55,6 @@ function navigatePlaylist(currentSong, direction, steps = 1) { return current; } -function detectLoop(playlist) { - // Floyd's cycle detection algorithm (tortoise and hare) - if (!playlist) return false; - - let slow = playlist; - let fast = playlist; - - while (fast && fast.next) { - slow = slow.next; // Move one step - fast = fast.next.next; // Move two steps - - if (slow === fast) { - console.log("šŸ”„ Loop detected in playlist!"); - return true; - } - } - - console.log("āœ… No loop detected - playlist is linear"); - return false; -} - // Helper function to create a test circular playlist function createCircularPlaylist() { const songA = new DoublySongNode("Song A", "Artist A"); @@ -93,9 +72,4 @@ function createCircularPlaylist() { console.log("=== Testing navigatePlaylist ==="); console.log("Forward 1 step from Hotel California:", navigatePlaylist(song2, "forward", 1)?.title); console.log("Backward 1 step from Stairway to Heaven:", navigatePlaylist(song3, "backward", 1)?.title); -console.log("Forward 2 steps from Bohemian Rhapsody:", navigatePlaylist(song1, "forward", 2)?.title); - -console.log("\n=== Testing detectLoop ==="); -console.log("Linear playlist has loop:", detectLoop(song1)); -const circularPlaylist = createCircularPlaylist(); -console.log("Circular playlist has loop:", detectLoop(circularPlaylist)); \ No newline at end of file +console.log("Forward 2 steps from Bohemian Rhapsody:", navigatePlaylist(song1, "forward", 2)?.title); \ No newline at end of file diff --git a/src/sections/06-linked-lists/03-linked-list-types/starterCode.js b/src/sections/06-linked-lists/03-linked-list-types/starterCode.js index 1a081e8..c953da8 100644 --- a/src/sections/06-linked-lists/03-linked-list-types/starterCode.js +++ b/src/sections/06-linked-lists/03-linked-list-types/starterCode.js @@ -46,27 +46,6 @@ function navigatePlaylist(currentSong, direction, steps = 1) { } */ -// ā±ļø Alex's Circular Playlist Challenge! -// šŸ”“ Uncomment the below code section and implement the required logic: - -/* -function detectLoop(playlist) { - // Detect if a playlist has a circular connection (Floyd's cycle detection) - // Return true if loop exists, false otherwise - - if (!playlist) return false; - - let slow = playlist; - let fast = playlist; - - // TODO: Implement the tortoise and hare algorithm - // Hint: Move slow pointer one step, fast pointer two steps - // If they meet, there's a loop - - return false; -} -*/ - // Helper function to create a test circular playlist function createCircularPlaylist() { const songA = new DoublySongNode("Song A", "Artist A"); @@ -86,9 +65,4 @@ console.log("=== Testing navigatePlaylist ==="); console.log("Forward 1 step from Hotel California:", navigatePlaylist(song2, "forward", 1)?.title); console.log("Backward 1 step from Stairway to Heaven:", navigatePlaylist(song3, "backward", 1)?.title); console.log("Forward 2 steps from Bohemian Rhapsody:", navigatePlaylist(song1, "forward", 2)?.title); - -console.log("\n=== Testing detectLoop ==="); -console.log("Linear playlist has loop:", detectLoop(song1)); -const circularPlaylist = createCircularPlaylist(); -console.log("Circular playlist has loop:", detectLoop(circularPlaylist)); */ \ No newline at end of file diff --git a/src/sections/06-linked-lists/03-linked-list-types/tests.js b/src/sections/06-linked-lists/03-linked-list-types/tests.js index a5beff2..dccd10c 100644 --- a/src/sections/06-linked-lists/03-linked-list-types/tests.js +++ b/src/sections/06-linked-lists/03-linked-list-types/tests.js @@ -99,48 +99,7 @@ const tests = [ } }, message: "navigatePlaylist should handle forward, backward, and multi-step navigation." - }, - { - name: "Test detectLoop function", - test: (code) => { - try { - const testCode = code + ` - let linearResult = false; - let circularResult = false; - - if (typeof detectLoop === 'function') { - // Test with linear playlist - linearResult = detectLoop(song1); - - // Test with circular playlist - const circularPlaylist = createCircularPlaylist(); - circularResult = detectLoop(circularPlaylist); - } - - return ({ linearResult, circularResult }); - `; - - const testResult = new Function(testCode)(); - - if (typeof testResult.linearResult === 'undefined') { - return new TestResult({ passed: false, message: "detectLoop function not found. Make sure to uncomment and implement it." }); - } - - if (testResult.linearResult !== false) { - return new TestResult({ passed: false, message: "detectLoop should return false for linear playlists" }); - } - - if (testResult.circularResult !== true) { - return new TestResult({ passed: false, message: "detectLoop should return true for circular playlists" }); - } - - return new TestResult({ passed: true }); - } catch (error) { - return new TestResult({ passed: false, message: error.message }); - } - }, - message: "detectLoop should correctly identify circular vs linear playlists using Floyd's algorithm." - }, + } ]; export { tests, TestResult }; \ No newline at end of file diff --git a/src/sections/06-linked-lists/04-linked-list-tradeoffs/checkpoint.jsx b/src/sections/06-linked-lists/04-linked-list-tradeoffs/checkpoint.jsx index 2afe975..6ba8d10 100644 --- a/src/sections/06-linked-lists/04-linked-list-tradeoffs/checkpoint.jsx +++ b/src/sections/06-linked-lists/04-linked-list-tradeoffs/checkpoint.jsx @@ -10,22 +10,22 @@ export default [ "Arrays require shifting elements for middle insertions", "Linked lists provide O(1) random access", "Arrays and linked lists have identical performance", - "Linked lists use less memory than arrays" ], correctAnswers: [0,1,2], - // explanation: { - // "Arrays provide O(1) random access": "āœ… Correct — Arrays can access any element by index in O(1) time.", - // "Linked lists provide O(1) insertion at beginning": "āœ… Correct — Just update head pointer in O(1) time.", - // "Arrays require shifting elements for middle insertions": "āœ… Correct — Elements after insertion point must shift.", - // "Linked lists provide O(1) random access": "āŒ Incorrect — Must traverse from head, O(n) time.", - // "Arrays and linked lists have identical performance": "āŒ Incorrect — They have different strengths and weaknesses.", - // "Linked lists use less memory than arrays": "āŒ Incorrect — Extra pointers increase memory usage." - // } + explanation: ( + + ) }, { type: QUESTION_TYPES.TEXT, questionJsx: "What is the time complexity for accessing the 50th element in a linked list?", correctAnswer: "O(n)", - // 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." + 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.") } ] \ No newline at end of file diff --git a/src/sections/06-linked-lists/04-linked-list-tradeoffs/index.jsx b/src/sections/06-linked-lists/04-linked-list-tradeoffs/index.jsx index 3d17997..0c5db38 100644 --- a/src/sections/06-linked-lists/04-linked-list-tradeoffs/index.jsx +++ b/src/sections/06-linked-lists/04-linked-list-tradeoffs/index.jsx @@ -1,7 +1,4 @@ import contentMd from './index.md?raw'; -import starterCode from './starterCode.js?raw'; -import solution from './solution.js?raw'; -import { tests } from './tests.js'; import questions from './checkpoint.jsx'; import { Checkpoint } from '@nss-workshops/nss-core'; @@ -11,10 +8,5 @@ export default { previousChapterId: "linked-types", nextChapterId: "linked-traversal", content: contentMd, - exercises: [{ - starterCode, - solution, - tests - }], quiz: {component: () => } }; \ No newline at end of file diff --git a/src/sections/06-linked-lists/04-linked-list-tradeoffs/index.md b/src/sections/06-linked-lists/04-linked-list-tradeoffs/index.md index ee6ce01..61000cb 100644 --- a/src/sections/06-linked-lists/04-linked-list-tradeoffs/index.md +++ b/src/sections/06-linked-lists/04-linked-list-tradeoffs/index.md @@ -176,17 +176,4 @@ Inserting at beginning: ↑ new head Just change two pointers! O(1) -``` - -## ā±ļø Alex's Performance Analysis Challenge! - -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." - -Jordan nodded enthusiastically. "This would help me understand exactly when to use each approach!" - -šŸ”“ **Uncomment the below code section in the editor šŸ‘‰:** -- Implement `comparePerformance()` to fill in different operations time complexity in big O notation -- **Click Run Code** -- **Inspect šŸ“‹ Console Output window and run test to check for correctness!** - -"This challenge will help you understand the practical implications of these performance differences," Maya explained. \ No newline at end of file +``` \ No newline at end of file diff --git a/src/sections/06-linked-lists/04-linked-list-tradeoffs/solution.js b/src/sections/06-linked-lists/04-linked-list-tradeoffs/solution.js deleted file mode 100644 index 402e238..0000000 --- a/src/sections/06-linked-lists/04-linked-list-tradeoffs/solution.js +++ /dev/null @@ -1,111 +0,0 @@ -// Song node for linked list implementation -class SongNode { - constructor(title, artist, duration) { - this.title = title; - this.artist = artist; - this.duration = duration; - this.next = null; - } -} - -// Array-based playlist for comparison -class ArrayPlaylist { - constructor() { - this.songs = []; - } - - addSong(title, artist, duration) { - this.songs.push({ title, artist, duration }); - } - - getSongAt(index) { - return this.songs[index] || null; - } - - insertAt(index, title, artist, duration) { - this.songs.splice(index, 0, { title, artist, duration }); - } -} - -// Linked list playlist for comparison -class LinkedPlaylist { - constructor() { - this.head = null; - this.size = 0; - } - - addSong(title, artist, duration) { - const newSong = new SongNode(title, artist, duration); - if (!this.head) { - this.head = newSong; - } else { - let current = this.head; - while (current.next) { - current = current.next; - } - current.next = newSong; - } - this.size++; - } - - getSongAt(index) { - let current = this.head; - for (let i = 0; i < index && current; i++) { - current = current.next; - } - return current; - } -} - -function comparePerformance(arrayPlaylist, linkedPlaylist, operation, index = 0) { - const results = { - operation: operation, - }; - - // Fill in the appropriate time complexity for each operation - switch (operation) { - case "access": - results.arrayComplexity = "O(1)"; // Direct index access - results.linkedComplexity = "O(n)"; // Must traverse from head - break; - - case "add_end": - results.arrayComplexity = "O(1)"; // Push to end of array - results.linkedComplexity = "O(n)"; // Must traverse to find end - break; - - case "add_beginning": - results.arrayComplexity = "O(n)"; // Must shift all elements - results.linkedComplexity = "O(1)"; // Just update head pointer - break; - } - - return results; -} - -// Test the function -const arrayPL = new ArrayPlaylist(); -const linkedPL = new LinkedPlaylist(); - -// Add some test songs -arrayPL.addSong("Test Song 1", "Artist 1", 180); -linkedPL.addSong("Test Song 1", "Artist 1", 180); - -console.log("=== Performance Comparison ==="); -console.log("Access:", comparePerformance(arrayPL, linkedPL, "access")); -console.log("Add to end:", comparePerformance(arrayPL, linkedPL, "add_end")); -console.log("Add to beginning:", comparePerformance(arrayPL, linkedPL, "add_beginning")); - -// Demonstrate the differences -console.log("\n=== Practical Examples ==="); - -// Array access is instant -console.log("Array access to index 0:", arrayPL.getSongAt(0)?.title || "Not found"); - -// Linked list access requires traversal -console.log("Linked list access to index 0:", linkedPL.getSongAt(0)?.title || "Not found"); - -console.log("\n=== Key Insights ==="); -console.log("āœ… Arrays excel at: Random access, adding to end"); -console.log("āœ… Linked Lists excel at: Adding to beginning, dynamic size"); -console.log("āš ļø Choose based on your primary use case!"); \ No newline at end of file diff --git a/src/sections/06-linked-lists/04-linked-list-tradeoffs/starterCode.js b/src/sections/06-linked-lists/04-linked-list-tradeoffs/starterCode.js deleted file mode 100644 index c8e5d18..0000000 --- a/src/sections/06-linked-lists/04-linked-list-tradeoffs/starterCode.js +++ /dev/null @@ -1,106 +0,0 @@ -// Song node for linked list implementation -class SongNode { - constructor(title, artist, duration) { - this.title = title; - this.artist = artist; - this.duration = duration; - this.next = null; - } -} - -// Array-based playlist for comparison -class ArrayPlaylist { - constructor() { - this.songs = []; - } - - addSong(title, artist, duration) { - this.songs.push({ title, artist, duration }); - } - - getSongAt(index) { - return this.songs[index] || null; - } - - insertAt(index, title, artist, duration) { - this.songs.splice(index, 0, { title, artist, duration }); - } -} - -// Linked list playlist for comparison -class LinkedPlaylist { - constructor() { - this.head = null; - this.size = 0; - } - - addSong(title, artist, duration) { - const newSong = new SongNode(title, artist, duration); - if (!this.head) { - this.head = newSong; - } else { - let current = this.head; - while (current.next) { - current = current.next; - } - current.next = newSong; - } - this.size++; - } - - getSongAt(index) { - let current = this.head; - for (let i = 0; i < index && current; i++) { - current = current.next; - } - return current; - } -} - -// ā±ļø Alex's Performance Analysis Challenge! -// šŸ”“ Uncomment the below code section and implement the required logic: - -/* -function comparePerformance(arrayPlaylist, linkedPlaylist, operation, index = 0) { - const results = { - operation: operation, - }; - - // TODO: Strings below should be replaced with the appropriate time complexity - // (e.g., O(1), O(n), O(n²), etc.) for the corresponding operation - - switch (operation) { - case "access": - results.arrayComplexity = "TODO"; - results.linkedComplexity = "TODO"; - break; - - case "add_end": - results.arrayComplexity = "TODO"; - results.linkedComplexity = "TODO"; - break; - - case "add_beginning": - results.arrayComplexity = "TODO"; - results.linkedComplexity = "TODO"; - break; - } - - return results; -} -*/ - -// Test your function (uncomment to test) -/* -const arrayPL = new ArrayPlaylist(); -const linkedPL = new LinkedPlaylist(); - -// Add some test songs -arrayPL.addSong("Test Song 1", "Artist 1", 180); -linkedPL.addSong("Test Song 1", "Artist 1", 180); - -console.log("=== Performance Comparison ==="); -console.log("Access:", comparePerformance(arrayPL, linkedPL, "access")); -console.log("Add to end:", comparePerformance(arrayPL, linkedPL, "add_end")); -console.log("Add to beginning:", comparePerformance(arrayPL, linkedPL, "add_beginning")); -*/ \ No newline at end of file diff --git a/src/sections/06-linked-lists/04-linked-list-tradeoffs/tests.js b/src/sections/06-linked-lists/04-linked-list-tradeoffs/tests.js deleted file mode 100644 index cc87d3c..0000000 --- a/src/sections/06-linked-lists/04-linked-list-tradeoffs/tests.js +++ /dev/null @@ -1,101 +0,0 @@ -// Test utilities for linked list tradeoffs exercises -class TestResult { - constructor({ passed, message }) { - this.passed = passed; - this.message = message; - } -} - -// Test functions for the linked list tradeoffs exercises -const tests = [ - { - name: "Test ArrayPlaylist and LinkedPlaylist basic functionality", - test: (code) => { - try { - const testCode = code + ` - // Test both playlist types - const arrayPL = new ArrayPlaylist(); - const linkedPL = new LinkedPlaylist(); - - arrayPL.addSong("Test Song", "Test Artist", 180); - linkedPL.addSong("Test Song", "Test Artist", 180); - - const arraySong = arrayPL.getSongAt(0); - const linkedSong = linkedPL.getSongAt(0); - - const arrayWorks = arraySong && arraySong.title === "Test Song"; - const linkedWorks = linkedSong && linkedSong.title === "Test Song"; - - return ({ arrayWorks, linkedWorks }); - `; - - const testResult = new Function(testCode)(); - - if (!testResult.arrayWorks) { - return new TestResult({ passed: false, message: "ArrayPlaylist not working correctly" }); - } - - if (!testResult.linkedWorks) { - return new TestResult({ passed: false, message: "LinkedPlaylist not working correctly" }); - } - - return new TestResult({ passed: true }); - } catch (error) { - return new TestResult({ passed: false, message: error.message }); - } - }, - message: "Both ArrayPlaylist and LinkedPlaylist should work correctly for basic operations." - }, - { - name: "Test comparePerformance function", - test: (code) => { - try { - const testCode = code + ` - const arrayPL = new ArrayPlaylist(); - const linkedPL = new LinkedPlaylist(); - - let accessResult = null; - let addEndResult = null; - let addBeginResult = null; - - if (typeof comparePerformance === 'function') { - accessResult = comparePerformance(arrayPL, linkedPL, "access"); - addEndResult = comparePerformance(arrayPL, linkedPL, "add_end"); - addBeginResult = comparePerformance(arrayPL, linkedPL, "add_beginning"); - } - - return ({ - accessResult: accessResult ? accessResult.arrayComplexity : null, - addEndResult: addEndResult ? addEndResult.arrayComplexity : null, - addBeginResult: addBeginResult ? addBeginResult.linkedComplexity : null - }); - `; - - const testResult = new Function(testCode)(); - - if (!testResult.accessResult) { - return new TestResult({ passed: false, message: "comparePerformance function not found. Make sure to uncomment and implement it." }); - } - - if (testResult.accessResult !== "O(1)") { - return new TestResult({ passed: false, message: "Array access should be O(1)" }); - } - - if (testResult.addEndResult !== "O(1)") { - return new TestResult({ passed: false, message: "Array add to end should be O(1)" }); - } - - if (testResult.addBeginResult !== "O(1)") { - return new TestResult({ passed: false, message: "Linked list add to beginning should be O(1)" }); - } - - return new TestResult({ passed: true }); - } catch (error) { - return new TestResult({ passed: false, message: error.message }); - } - }, - message: "comparePerformance should correctly analyze time complexities for different operations." - } -]; - -export { tests, TestResult }; \ No newline at end of file diff --git a/src/sections/06-linked-lists/05-node-based-traversal/index.md b/src/sections/06-linked-lists/05-node-based-traversal/index.md index 9832342..74379eb 100644 --- a/src/sections/06-linked-lists/05-node-based-traversal/index.md +++ b/src/sections/06-linked-lists/05-node-based-traversal/index.md @@ -113,7 +113,7 @@ Alex studied the patterns. "I see! Each search function uses the same basic trav "Exactly," Maya said. "The traversal pattern is consistent, but the logic inside the loop changes based on what we need to accomplish." -## ā±ļø Alex's First Traversal Challenge! +## ā±ļø Alex's Traversal Challenge! Maya pulled out her tablet. "Alex, let's put this into practice. I want you to implement a function that can calculate the total duration of a playlist." @@ -127,89 +127,6 @@ Jordan nodded enthusiastically. "This would be really useful for our library's m "This challenge reinforces the fundamental traversal pattern while solving a practical problem," Maya explained. -## Advanced Traversal: Two-Pointer Techniques - -After Alex completed the first challenge, Maya introduced a more sophisticated concept: - -"Sometimes we need to use multiple pointers to solve complex problems. Let me show you a classic example - finding the middle song of a playlist without knowing its length." - -```javascript -function findMiddleSong(head) { - if (!head) { - console.log("šŸ“­ Playlist is empty"); - return null; - } - - let slow = head; // Moves one step at a time - let fast = head; // Moves two steps at a time - - // When fast reaches the end, slow will be at the middle - while (fast !== null && fast.next !== null) { - slow = slow.next; - fast = fast.next.next; - } - - console.log(`šŸŽÆ Middle song: ${slow.toString()}`); - return slow; -} -``` - -Alex was fascinated. "How does that work?" - -Maya drew a diagram on the whiteboard: - -``` -Step 1: [A] → [B] → [C] → [D] → [E] → null - ↑ ↑ - slow fast - -Step 2: [A] → [B] → [C] → [D] → [E] → null - ↑ ↑ - slow fast - -Step 3: [A] → [B] → [C] → [D] → [E] → null - ↑ ↑ - slow fast (null) - -Result: slow is at the middle! -``` - -"The fast pointer moves twice as fast as the slow pointer," Maya explained. "When the fast pointer reaches the end, the slow pointer is exactly at the middle." - -Jordan was amazed. "That's brilliant! We can find the middle without counting the total length first." - -## ā±ļø Alex's Second Traversal Challenge! - -"Now for a more complex challenge," Maya said. "Jordan wants to implement a feature that can remove songs from the playlist." - -Jordan explained: "Sometimes users want to remove songs they don't like, or we need to remove duplicates. But removing from a linked list is trickier than inserting." - -šŸ”“ **Uncomment the below code section in the editor šŸ‘‰:** -- Implement `removeSongByTitle()` to remove a song from the playlist -- Handle the special case of removing the first song -- **Click Run Code** -- **Inspect šŸ“‹ Console Output window and run test to check for correctness!** - -"This challenge teaches you about the careful pointer manipulation needed for safe removal," Maya explained. - -## ā±ļø Alex's Advanced Traversal Challenge! - -"For your final challenge," Maya said with a smile, "I want you to implement a function that can reverse a playlist - make it play backwards!" - -Jordan's eyes lit up. "That would be amazing for creating 'reverse chronology' playlists!" - -šŸ”“ **Uncomment the below code section in the editor šŸ‘‰:** -- Implement `reversePlaylist()` to reverse the order of songs -- Use three pointers: previous, current, and next -- **Click Run Code** -- **Inspect šŸ“‹ Console Output window and run test to check for correctness!** - -"This challenge teaches you about complex pointer manipulation and is a classic computer science problem," Maya explained. - -## Common Traversal Pitfalls and Solutions - -Maya then showed them common mistakes and how to avoid them: - ### Pitfall 1: Losing the Head Reference ```javascript // āŒ Wrong - loses the original head @@ -247,41 +164,4 @@ function goodAccess(head) { current = current.next; } } -``` - -## Real-World Applications of Traversal Patterns - -Maya showed them how these patterns apply beyond music: - -### Web Scraping -"Web crawlers use similar traversal patterns to follow links between web pages." - -### File System Navigation -"File explorers traverse directory structures using these same principles." - -### Game Development -"Game engines traverse scene graphs to render objects in the correct order." - -### Database Systems -"Database engines use traversal algorithms to execute queries efficiently." - -## Key Insights from Playlist Traversal - -By the end of their session, Alex had mastered several important concepts: - -- **Basic traversal** is the foundation for all linked list operations -- **Search patterns** use traversal with conditional logic -- **Two-pointer techniques** solve complex problems efficiently -- **Insertion and deletion** require careful pointer manipulation -- **Common pitfalls** can be avoided with proper null checking -- **Real-world applications** exist across many domains - -Jordan was already implementing these patterns in their playlist system. "I can't believe how much more powerful the system is now! Users can search, analyze, and manipulate playlists in ways I never thought possible." - -"That's the beauty of understanding fundamental algorithms," Maya said. "Once you master the basic patterns, you can solve increasingly complex problems." - -As they packed up, Alex reflected on the journey. "It's amazing how something as simple as following pointers can enable such sophisticated operations." - -Maya smiled. "Tomorrow, we'll explore how to implement a complete playlist system from scratch, bringing together everything you've learned about linked lists." - -The mastery of traversal patterns had opened up a world of possibilities, transforming simple song chains into powerful, dynamic playlist systems. \ No newline at end of file +``` \ No newline at end of file diff --git a/src/sections/06-linked-lists/05-node-based-traversal/solution.js b/src/sections/06-linked-lists/05-node-based-traversal/solution.js index 0672188..c0fc52a 100644 --- a/src/sections/06-linked-lists/05-node-based-traversal/solution.js +++ b/src/sections/06-linked-lists/05-node-based-traversal/solution.js @@ -14,17 +14,6 @@ class SongNode { } } -// Create a sample playlist -const song1 = new SongNode("Bohemian Rhapsody", "Queen", 355); -const song2 = new SongNode("Hotel California", "Eagles", 391); -const song3 = new SongNode("Stairway to Heaven", "Led Zeppelin", 482); -const song4 = new SongNode("Sweet Child O' Mine", "Guns N' Roses", 356); - -// Connect the songs -song1.next = song2; -song2.next = song3; -song3.next = song4; - function calculatePlaylistDuration(head) { // Calculate the total duration of all songs in the playlist let totalDuration = 0; @@ -41,83 +30,4 @@ function calculatePlaylistDuration(head) { console.log(`šŸ“Š Total playlist duration: ${minutes}:${seconds.toString().padStart(2, '0')} (${totalDuration}s)`); return totalDuration; -} - -function removeSongByTitle(head, targetTitle) { - // Handle empty playlist - if (!head) return null; - - // Handle removing the first song - if (head.title.toLowerCase() === targetTitle.toLowerCase()) { - console.log(`šŸ—‘ļø Removed: ${head.toString()}`); - return head.next; - } - - // Find and remove the target song from the middle or end - let current = head; - - while (current.next !== null) { - if (current.next.title.toLowerCase() === targetTitle.toLowerCase()) { - const removedSong = current.next; - current.next = removedSong.next; - console.log(`šŸ—‘ļø Removed: ${removedSong.toString()}`); - return head; - } - current = current.next; - } - - console.log(`āŒ Song "${targetTitle}" not found in playlist`); - return head; -} - -function reversePlaylist(head) { - let previous = null; - let current = head; - let next = null; - - console.log("šŸ”„ Reversing playlist..."); - - while (current !== null) { - // Store the next node - next = current.next; - - // Reverse the link - current.next = previous; - - // Move pointers forward - previous = current; - current = next; - } - - console.log("āœ… Playlist reversed!"); - return previous; // Previous is now the new head -} - -// Test the functions -console.log("=== Testing calculatePlaylistDuration ==="); -const totalDuration = calculatePlaylistDuration(song1); -console.log(`Total duration: ${totalDuration} seconds`); - -console.log("\n=== Testing removeSongByTitle ==="); -let modifiedPlaylist = removeSongByTitle(song1, "Hotel California"); -console.log("After removing Hotel California:"); -let current = modifiedPlaylist; -while (current) { - console.log(current.toString()); - current = current.next; -} - -console.log("\n=== Testing reversePlaylist ==="); -const reversedPlaylist = reversePlaylist(song1); -console.log("Reversed playlist:"); -current = reversedPlaylist; -while (current) { - console.log(current.toString()); - current = current.next; -} - -console.log("\n=== Key Traversal Patterns Demonstrated ==="); -console.log("āœ… Basic traversal with accumulation (calculatePlaylistDuration)"); -console.log("āœ… Search and remove with pointer manipulation (removeSongByTitle)"); -console.log("āœ… Complex pointer reversal (reversePlaylist)"); -console.log("āœ… Safe null checking throughout all operations"); \ No newline at end of file +} \ No newline at end of file diff --git a/src/sections/06-linked-lists/05-node-based-traversal/starterCode.js b/src/sections/06-linked-lists/05-node-based-traversal/starterCode.js index 84d6472..3586aa8 100644 --- a/src/sections/06-linked-lists/05-node-based-traversal/starterCode.js +++ b/src/sections/06-linked-lists/05-node-based-traversal/starterCode.js @@ -14,17 +14,6 @@ class SongNode { } } -// Create a sample playlist -const song1 = new SongNode("Bohemian Rhapsody", "Queen", 355); -const song2 = new SongNode("Hotel California", "Eagles", 391); -const song3 = new SongNode("Stairway to Heaven", "Led Zeppelin", 482); -const song4 = new SongNode("Sweet Child O' Mine", "Guns N' Roses", 356); - -// Connect the songs -song1.next = song2; -song2.next = song3; -song3.next = song4; - // ā±ļø Alex's First Traversal Challenge! // šŸ”“ Uncomment the below code section and implement the required logic: @@ -41,72 +30,4 @@ function calculatePlaylistDuration(head) { return totalDuration; } -*/ - -// ā±ļø Alex's Second Traversal Challenge! -// šŸ”“ Uncomment the below code section and implement the required logic: - -/* -function removeSongByTitle(head, targetTitle) { - // Remove the first song with the matching title from the playlist - // Return the new head of the playlist - - // Handle empty playlist - if (!head) return null; - - // Handle removing the first song - if (head.title.toLowerCase() === targetTitle.toLowerCase()) { - console.log(`šŸ—‘ļø Removed: ${head.toString()}`); - return head.next; - } - - // TODO: Find and remove the target song from the middle or end - // Hint: Keep track of the previous node to update its next pointer - - return head; -} -*/ - -// ā±ļø Alex's Advanced Traversal Challenge! -// šŸ”“ Uncomment the below code section and implement the required logic: - -/* -function reversePlaylist(head) { - // Reverse the order of songs in the playlist - // Return the new head of the reversed playlist - - let previous = null; - let current = head; - let next = null; - - // TODO: Reverse the links between nodes - // Hint: For each node, make it point to the previous node instead of the next - - return previous; // Previous becomes the new head -} -*/ - -// Test your functions (uncomment to test) -/* -console.log("=== Testing calculatePlaylistDuration ==="); -const totalDuration = calculatePlaylistDuration(song1); -console.log(`Total duration: ${totalDuration} seconds`); - -console.log("\n=== Testing removeSongByTitle ==="); -let modifiedPlaylist = removeSongByTitle(song1, "Hotel California"); -console.log("After removing Hotel California:"); -let current = modifiedPlaylist; -while (current) { - console.log(current.toString()); - current = current.next; -} - -console.log("\n=== Testing reversePlaylist ==="); -const reversedPlaylist = reversePlaylist(song1); -console.log("Reversed playlist:"); -current = reversedPlaylist; -while (current) { - console.log(current.toString()); - current = current.next; -} */ \ No newline at end of file diff --git a/src/sections/06-linked-lists/05-node-based-traversal/tests.js b/src/sections/06-linked-lists/05-node-based-traversal/tests.js index c118216..559000a 100644 --- a/src/sections/06-linked-lists/05-node-based-traversal/tests.js +++ b/src/sections/06-linked-lists/05-node-based-traversal/tests.js @@ -8,68 +8,30 @@ class TestResult { // Test functions for the node-based traversal exercises const tests = [ - { - name: "Test SongNode creation and playlist setup", - test: (code) => { - try { - const testCode = code + ` - // Test song node creation - const testSong = new SongNode("Test Song", "Test Artist", 180); - const songString = testSong.toString(); - const hasDuration = testSong.duration === 180; - - // Test playlist linking - const hasNext = song1.next === song2; - const chainWorks = song1.next.next === song3; - - return ({ songString, hasDuration, hasNext, chainWorks }); - `; - - const testResult = new Function(testCode)(); - - if (!testResult.songString.includes("Test Song - Test Artist (3:00)")) { - return new TestResult({ passed: false, message: "SongNode toString() not formatting correctly" }); - } - - if (!testResult.hasDuration) { - return new TestResult({ passed: false, message: "SongNode duration not stored correctly" }); - } - - if (!testResult.hasNext) { - return new TestResult({ passed: false, message: "Playlist linking not working correctly" }); - } - - if (!testResult.chainWorks) { - return new TestResult({ passed: false, message: "Playlist chain not connected properly" }); - } - - return new TestResult({ passed: true }); - } catch (error) { - return new TestResult({ passed: false, message: error.message }); - } - }, - message: "SongNode should work correctly with duration formatting and playlist linking." - }, { name: "Test calculatePlaylistDuration function", test: (code) => { try { const testCode = code + ` let totalDuration = 0; + // Create a test playlist + const testSong1 = new SongNode("Song A", "Artist A", 355); + const testSong2 = new SongNode("Song B", "Artist B", 391); + const testSong3 = new SongNode("Song C", "Artist C", 482); + const testSong4 = new SongNode("Song D", "Artist D", 356); - if (typeof calculatePlaylistDuration === 'function') { - totalDuration = calculatePlaylistDuration(song1); - } + testSong1.next = testSong2; + testSong2.next = testSong3; + testSong3.next = testSong4; + + totalDuration = calculatePlaylistDuration(testSong1); return ({ totalDuration }); `; - const testResult = new Function(testCode)(); - if (typeof testResult.totalDuration === 'undefined') { return new TestResult({ passed: false, message: "calculatePlaylistDuration function not found. Make sure to uncomment and implement it." }); } - // Expected total: 355 + 391 + 482 + 356 = 1584 seconds if (testResult.totalDuration !== 1584) { return new TestResult({ passed: false, message: `Expected total duration of 1584 seconds, got ${testResult.totalDuration}` }); @@ -81,114 +43,7 @@ const tests = [ } }, message: "calculatePlaylistDuration should correctly sum all song durations." - }, - { - name: "Test removeSongByTitle function", - test: (code) => { - try { - const testCode = code + ` - // Create a test playlist - const testSong1 = new SongNode("Song A", "Artist A", 180); - const testSong2 = new SongNode("Song B", "Artist B", 200); - const testSong3 = new SongNode("Song C", "Artist C", 220); - - testSong1.next = testSong2; - testSong2.next = testSong3; - - let newHead = testSong1; - let removedMiddle = false; - let removedFirst = false; - - if (typeof removeSongByTitle === 'function') { - // Remove middle song - newHead = removeSongByTitle(newHead, "Song B"); - removedMiddle = newHead.next && newHead.next.title === "Song C"; - - // Remove first song - newHead = removeSongByTitle(newHead, "Song A"); - removedFirst = newHead && newHead.title === "Song C"; - } - - return ({ removedMiddle, removedFirst }); - `; - - const testResult = new Function(testCode)(); - - if (typeof testResult.removedMiddle === 'undefined') { - return new TestResult({ passed: false, message: "removeSongByTitle function not found. Make sure to uncomment and implement it." }); - } - - if (!testResult.removedMiddle) { - return new TestResult({ passed: false, message: "removeSongByTitle should properly remove songs from the middle" }); - } - - if (!testResult.removedFirst) { - return new TestResult({ passed: false, message: "removeSongByTitle should properly remove the first song and return new head" }); - } - - return new TestResult({ passed: true }); - } catch (error) { - return new TestResult({ passed: false, message: error.message }); - } - }, - message: "removeSongByTitle should remove songs from any position in the playlist." - }, - { - name: "Test reversePlaylist function", - test: (code) => { - try { - const testCode = code + ` - // Create a test playlist - const testSong1 = new SongNode("First", "Artist", 180); - const testSong2 = new SongNode("Second", "Artist", 200); - const testSong3 = new SongNode("Third", "Artist", 220); - - testSong1.next = testSong2; - testSong2.next = testSong3; - - let reversedHead = null; - let firstIsThird = false; - let secondIsSecond = false; - let thirdIsFirst = false; - - if (typeof reversePlaylist === 'function') { - reversedHead = reversePlaylist(testSong1); - - if (reversedHead) { - firstIsThird = reversedHead.title === "Third"; - secondIsSecond = reversedHead.next && reversedHead.next.title === "Second"; - thirdIsFirst = reversedHead.next && reversedHead.next.next && reversedHead.next.next.title === "First"; - } - } - - return ({ firstIsThird, secondIsSecond, thirdIsFirst }); - `; - - const testResult = new Function(testCode)(); - - if (typeof testResult.firstIsThird === 'undefined') { - return new TestResult({ passed: false, message: "reversePlaylist function not found. Make sure to uncomment and implement it." }); - } - - if (!testResult.firstIsThird) { - return new TestResult({ passed: false, message: "After reversal, first song should be 'Third'" }); - } - - if (!testResult.secondIsSecond) { - return new TestResult({ passed: false, message: "After reversal, second song should be 'Second'" }); - } - - if (!testResult.thirdIsFirst) { - return new TestResult({ passed: false, message: "After reversal, third song should be 'First'" }); - } - - return new TestResult({ passed: true }); - } catch (error) { - return new TestResult({ passed: false, message: error.message }); - } - }, - message: "reversePlaylist should correctly reverse the order of all songs." - }, + } ]; export { tests, TestResult }; \ No newline at end of file diff --git a/src/sections/06-linked-lists/06-info-sheet/index.md b/src/sections/06-linked-lists/06-info-sheet/index.md index b29b804..e6f00d7 100644 --- a/src/sections/06-linked-lists/06-info-sheet/index.md +++ b/src/sections/06-linked-lists/06-info-sheet/index.md @@ -1,4 +1,3 @@ -# Linked Lists - Operations & Complexity Info Sheet ## Common Linked List Operations diff --git a/src/sections/06-linked-lists/07-supplemental-materials/index.md b/src/sections/06-linked-lists/07-supplemental-materials/index.md index bcadedf..3cd30c0 100644 --- a/src/sections/06-linked-lists/07-supplemental-materials/index.md +++ b/src/sections/06-linked-lists/07-supplemental-materials/index.md @@ -1,5 +1,3 @@ -# Supplemental Materials: Linked Lists & Pointer Manipulation - ### Recommended Podcast Episode **[Linked Lists in Your Apartment](https://www.codenewbie.org/basecs/7)** diff --git a/src/sections/06-linked-lists/08-glossary/index.jsx b/src/sections/06-linked-lists/08-glossary/index.jsx index 5ea1c83..7f0a346 100644 --- a/src/sections/06-linked-lists/08-glossary/index.jsx +++ b/src/sections/06-linked-lists/08-glossary/index.jsx @@ -10,9 +10,6 @@ const data = [ { term: "Doubly Linked List", definition: "A playlist where each song knows both the next song AND the previous song. This lets you move forward and backward through your playlist.", week: "4" }, { term: "Circular Linked List", definition: "A playlist that loops forever - when you reach the last song, it automatically goes back to the first song. Perfect for party music!", week: "4" }, { term: "Traversal", definition: "Moving through a linked list from one node to the next, like playing through all songs in your playlist from start to finish.", week: "4" }, - { term: "Insertion", definition: "Adding a new song to your playlist. You can add it at the beginning, end, or anywhere in the middle by updating the pointer connections.", week: "4" }, - { term: "Deletion", definition: "Removing a song from your playlist by updating the pointers so they skip over the unwanted song, effectively removing it from the chain.", week: "4" }, - { term: "LIFO", definition: "Last In, First Out - like a stack of books where you take from the top. The most recently added item is the first one you remove.", week: "4" }, { term: "O(1)", definition: "Constant time - an operation that takes the same amount of time whether you have 10 songs or 10,000 songs in your playlist.", week: "4" }, { term: "O(n)", definition: "Linear time - an operation that takes longer as your playlist gets bigger. Finding the 50th song takes longer than finding the 5th song.", week: "4" }, { term: "Null", definition: "A special value meaning 'nothing' or 'empty'. Used to mark the end of a playlist - the last song's 'next' pointer is null.", week: "4" } diff --git a/src/sections/06-linked-lists/09-checkpoint/checkpoint.jsx b/src/sections/06-linked-lists/09-checkpoint/checkpoint.jsx index ccfebae..94e8093 100644 --- a/src/sections/06-linked-lists/09-checkpoint/checkpoint.jsx +++ b/src/sections/06-linked-lists/09-checkpoint/checkpoint.jsx @@ -1,32 +1,6 @@ import { QUESTION_TYPES } from '@nss-workshops/nss-core'; export default [ - // āœ… SCENARIO 1 - { - type: QUESTION_TYPES.RADIO, - questionJsx: "You're building a ride-share app where users are matched in the order they request a ride. Which data structure would best model this?", - answers: [ - "Stack – LIFO for faster access", - "Linked List – Flexible insert/delete", - "Queue – FIFO to serve in order", - "Hash Map – Match by request ID" - ], - correctAnswer: 2 - }, - - // āœ… SCENARIO 2 - { - type: QUESTION_TYPES.RADIO, - questionJsx: "You're building a browser navigation feature. Users should be able to move backward and forward through visited pages. Which structure fits best?", - answers: [ - "Singly Linked List", - "Queue", - "Doubly Linked List", - "Stack" - ], - correctAnswer: 2 - }, - // āœ… BIG O 1 { type: QUESTION_TYPES.RADIO, @@ -56,7 +30,16 @@ export default [ // āœ… CODE SNIPPET 1 { type: QUESTION_TYPES.RADIO, - questionJsx: "Fill in the blanks to iterate through a singly linked list:\n\n```\nlet current = head;\nwhile (__________) {\n console.log(current.value);\n current = __________;\n}\n```", + questionJsx:
+

Fill in the blanks to iterate through a singly linked list:

+
+{`let current = head;
+while (_________) {
+  console.log(current.value);
+  current = __________;
+}`}
+  
+
, answers: [ "`current !== null`, `current.next`", "`head !== null`, `head.next`", @@ -69,7 +52,17 @@ export default [ // āœ… CODE SNIPPET 2 { type: QUESTION_TYPES.RADIO, - questionJsx: "What code correctly adds a node with value `val` to the head of a singly linked list?\n\n```\nlet newNode = new Node(val);\nnewNode.next = ____________;\nhead = ____________;\n```", + questionJsx:
+

+ What code correctly adds a node with value val to the head of a singly linked list? +

+
+{`let newNode = new Node(val);
+newNode.next = ____________;
+head = ____________;
+`}
+  
+
, answers: [ "`null`, `newNode`", "`head`, `newNode`", diff --git a/src/sections/06-linked-lists/_b4f7e9a2/index.jsx b/src/sections/06-linked-lists/_b4f7e9a2/index.jsx index 0cb825a..daed3d9 100644 --- a/src/sections/06-linked-lists/_b4f7e9a2/index.jsx +++ b/src/sections/06-linked-lists/_b4f7e9a2/index.jsx @@ -119,18 +119,6 @@ const questions = [ head.next = new Node(arr[i] * 2); } return head; -}`} - - , -
- D) -
-{`function buildAndDouble(arr) {
-  let nodes = arr.map(val => new Node(val * 2));
-  for (let i = 0; i < nodes.length - 1; i++) {
-    nodes[i].next = nodes[i + 1];
-  }
-  return nodes[0];
 }`}
         
@@ -197,21 +185,6 @@ const questions = [
  • Only creates two nodes total (head and one next node)
  • Overwrites head.next instead of properly chaining all nodes
  • - -

    D. Incorrect - Uses Built-in Methods

    -
    -{`function buildAndDouble(arr) {
    -  let nodes = arr.map(val => new Node(val * 2));  // Built-in method
    -  for (let i = 0; i < nodes.length - 1; i++) {
    -    nodes[i].next = nodes[i + 1];
    -  }
    -  return nodes[0];
    -}`}
    -        
    -
      -
    • Uses array.map() which violates "without built-in libraries" requirement
    • -
    • Doesn't demonstrate manual iteration through the linked list
    • -
    ) }, @@ -270,7 +243,7 @@ const questions = [
    • Scenario A: Browser history (back/forward navigation)
    • Scenario B: Round-robin task scheduler
    • -
    • Scenario C: Simple queue (FIFO)
    • +
    • Scenario C: Automatic Book Page Feeder into Scanner
    ), @@ -302,11 +275,11 @@ const questions = [
  • Perfect for repeating, cyclical processes
  • -

    Scenario C - Simple Queue (FIFO): Singly Linked List āœ…

    +

    Scenario C - Automatic Book Page Feeder into Scanner: Singly Linked List āœ…

    • Only need to add at tail and remove from head
    • No backward traversal needed
    • -
    • Minimal memory overhead (no prev pointers)
    • +
    • Minimal memory overhead (no prev pointers)
    • Simple and efficient for unidirectional processing