Show description
CSE240 - Level 5: The Linked List Labyrinth
CSE240 - Level 5: The Linked List Labyrinth
CSE240: Linked List Labyrinth
Your Complete Guide to HW5
LVL 1: Structs
LVL 2: Pointers
LVL 3: Linked Lists
Boss Battles
Final Code
LEVEL 1: FORGING YOUR CHARACTER (Structs & Enums)
Before we can venture into the labyrinth, we need to define our character's attributes. In C, we use a struct to group different data types into a single "record". For this quest, our character is a studentRecord.
The `studentRecord` Blueprint
Our struct holds all the essential stats for one student. Notice how it contains character arrays for strings, an integer for the ID, and a special enum type for the school year.
struct studentRecord {
char studentName[MAX_NAME_LENGTH];
char major[MAX_NAME_LENGTH];
schoolYearType schoolYear; // This is our special Enum type!
unsigned int IDNumber;
struct studentRecord* next; // The magic pointer that links to the next character!
};
The `enum` Scroll
An enum (enumeration) is a way to create a set of named integer constants. It makes our code more readable than using magic numbers like 0, 1, 2, 3. Here, `freshman` is secretly `0`, `sophomore` is `1`, and so on.
typedef enum { freshman = 0, sophomore, junior, senior } schoolYearType;
LEVEL 2: MASTERING THE POINTER WAND (Memory Management)
Pointers are the magic wands of C. They don't hold data themselves; they hold the memory address *where* data lives. To create new student records on the fly, we must master memory allocation.
Casting `malloc()`
The malloc() spell (memory allocation) reserves a chunk of memory from the "heap". We tell it how much space we need (the size of one `studentRecord`), and it gives us back a generic pointer to that space. We then "cast" it to the correct pointer type.
// Reserve memory for one new student and get a pointer to it.
struct studentRecord* newNode = (struct studentRecord*)malloc(sizeof(struct studentRecord));
The `free()` Spell of Banishment
Memory you allocate with `malloc()` is not automatically cleaned up! If you lose the pointer to it, that memory becomes a "memory leak," draining your system's power. The free() spell is essential.…
CSE240 - Level 5: The Linked List Labyrinth
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSE240 - Level 5: The Linked List Labyrinth</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=VT323&display=swap" rel="stylesheet">
<style>
:root {
--bg-color: #12121e;
--primary-text: #e0e0e0;
--header-text: #a2facf;
--accent-color-1: #ff00ff; /* Magenta */
--accent-color-2: #ffff00; /* Yellow */
--accent-color-3: #00ffff; /* Cyan */
--container-bg: #1e1e3f;
--border-color: #4f4f7a;
--code-bg: #0d0d1a;
}
/* General Body Styling */
body {
background-color: var(--bg-color);
color: var(--primary-text);
font-family: 'VT323', monospace;
font-size: 20px;
line-height: 1.6;
margin: 0;
padding: 0;
overflow-x: hidden;
}
/* 8-bit style containers */
.container {
max-width: 900px;
margin: 40px auto;
padding: 25px;
background-color: var(--container-bg);
border: 3px solid var(--border-color);
box-shadow: 6px 6px 0px var(--accent-color-1);
transition: transform 0.2s ease;
}
.container:hover {
transform: translate(-3px, -3px);
box-shadow: 9px 9px 0px var(--accent-color-1);
}
/* Typography */
h1, h2, h3 {
font-family: 'Press Start 2P', cursive;
color: var(--header-text);
text-shadow: 3px 3px 0px var(--accent-color-1);
margin-bottom: 20px;
}
h1 { font-size: 2.5rem; text-align: center; }
h2 { font-size: 1.8rem; color: var(--accent-color-2); border-bottom: 3px solid var(--border-color); padding-bottom: 10px;}
h3 { font-size: 1.4rem; color: var(--accent-color-3); }
a {
color: var(--accent-color-2);
text-decoration: none;
transition: all 0.2s ease;
}
a:hover {
background-color: var(--accent-color-2);
color: var(--bg-color);
text-shadow: none;
}
/* Header section with typing animation */
header {
text-align: center;
padding: 60px 20px;
border-bottom: 5px solid var(--border-color);
}
.typing-effect {
display: inline-block;
overflow: hidden;
white-space: nowrap;
border-right: .15em solid var(--accent-color-2);
animation: typing 3.5s steps(40, end), blink-caret .75s step-end infinite;
}
@keyframes typing {
from { width: 0 }
to { width: 100% }
}
@keyframes blink-caret {
from, to { border-color: transparent }
50% { border-color: var(--accent-color-2); }
}
/* Navigation Bar */
nav {
background-color: var(--container-bg);
border-bottom: 3px solid var(--border-color);
padding: 10px 0;
position: sticky;
top: 0;
z-index: 1000;
text-align: center;
}
nav a {
font-family: 'Press Start 2P', cursive;
font-size: 0.8rem;
margin: 0 15px;
padding: 5px 10px;
}
/* Code Blocks */
pre {
background-color: var(--code-bg);
border: 2px solid var(--border-color);
padding: 20px;
font-family: 'VT323', monospace;
font-size: 18px;
white-space: pre-wrap;
word-wrap: break-word;
box-shadow: inset 4px 4px 0px rgba(0,0,0,0.3);
position: relative;
}
.code-comment {
color: #888899; /* Grey for comments */
}
.code-keyword {
color: #ff79c6; /* Pink for keywords */
}
.code-type {
color: #8be9fd; /* Cyan for types */
}
.code-function {
color: #50fa7b; /* Green for function names */
}
.code-string {
color: #f1fa8c; /* Yellow for strings */
}
.copy-btn {
position: absolute;
top: 10px;
right: 10px;
background-color: var(--accent-color-3);
color: var(--bg-color);
border: 2px solid var(--border-color);
padding: 5px 10px;
font-family: 'Press Start 2P', cursive;
font-size: 12px;
cursor: pointer;
box-shadow: 3px 3px 0px var(--border-color);
transition: all 0.1s ease;
}
.copy-btn:active {
transform: translate(3px, 3px);
box-shadow: none;
}
/* Scroll reveal animation */
.reveal {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}
.reveal.active {
opacity: 1;
transform: translateY(0);
}
/* Image styling */
img {
max-width: 100%;
height: auto;
border: 3px solid var(--border-color);
margin: 20px 0;
}
ul {
list-style-type: none;
padding-left: 0;
}
li::before {
content: '>';
color: var(--accent-color-2);
font-weight: bold;
display: inline-block;
width: 1em;
margin-left: -1em;
}
/* Footer */
footer {
text-align: center;
padding: 40px 20px;
margin-top: 50px;
border-top: 5px solid var(--border-color);
font-family: 'Press Start 2P', cursive;
font-size: 0.8rem;
color: var(--accent-color-3);
}
</style>
</head>
<body>
<header>
<h1><span class="typing-effect">CSE240: Linked List Labyrinth</span></h1>
<p style="font-size: 24px; color: var(--accent-color-2);">Your Complete Guide to HW5</p>
</header>
<nav id="navbar">
<a href="#level-1">LVL 1: Structs</a>
<a href="#level-2">LVL 2: Pointers</a>
<a href="#level-3">LVL 3: Linked Lists</a>
<a href="#boss-battles">Boss Battles</a>
<a href="#final-code">Final Code</a>
</nav>
<main>
<div id="level-1" class="container reveal">
<h2>LEVEL 1: FORGING YOUR CHARACTER (Structs & Enums)</h2>
<p>
Before we can venture into the labyrinth, we need to define our character's attributes. In C, we use a <code>struct</code> to group different data types into a single "record". For this quest, our character is a <code>studentRecord</code>.
</p>
<h3>The `studentRecord` Blueprint</h3>
<p>
Our struct holds all the essential stats for one student. Notice how it contains character arrays for strings, an integer for the ID, and a special <code>enum</code> type for the school year.
</p>
<pre><code class="language-c"><span class="code-keyword">struct</span> <span class="code-type">studentRecord</span> {
<span class="code-type">char</span> studentName[MAX_NAME_LENGTH];
<span class="code-type">char</span> major[MAX_NAME_LENGTH];
<span class="code-type">schoolYearType</span> schoolYear; <span class="code-comment">// This is our special Enum type!</span>
<span class="code-type">unsigned int</span> IDNumber;
<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* next; <span class="code-comment">// The magic pointer that links to the next character!</span>
};</code></pre>
<h3>The `enum` Scroll</h3>
<p>
An <code>enum</code> (enumeration) is a way to create a set of named integer constants. It makes our code more readable than using magic numbers like 0, 1, 2, 3. Here, `freshman` is secretly `0`, `sophomore` is `1`, and so on.
</p>
<pre><code class="language-c"><span class="code-keyword">typedef</span> <span class="code-keyword">enum</span> { freshman = 0, sophomore, junior, senior } <span class="code-type">schoolYearType</span>;</code></pre>
</div>
<div id="level-2" class="container reveal">
<h2>LEVEL 2: MASTERING THE POINTER WAND (Memory Management)</h2>
<p>
Pointers are the magic wands of C. They don't hold data themselves; they hold the memory address *where* data lives. To create new student records on the fly, we must master memory allocation.
</p>
<h3>Casting `malloc()`</h3>
<p>
The <code>malloc()</code> spell (memory allocation) reserves a chunk of memory from the "heap". We tell it how much space we need (the size of one `studentRecord`), and it gives us back a generic pointer to that space. We then "cast" it to the correct pointer type.
</p>
<pre><code class="language-c"><span class="code-comment">// Reserve memory for one new student and get a pointer to it.</span>
<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* newNode = (<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>*)<span class="code-function">malloc</span>(<span class="code-keyword">sizeof</span>(<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>));</code></pre>
<h3>The `free()` Spell of Banishment</h3>
<p>
Memory you allocate with `malloc()` is not automatically cleaned up! If you lose the pointer to it, that memory becomes a "memory leak," draining your system's power. The <code>free()</code> spell is essential. You must cast it on every piece of memory you're done with to return it to the system.
</p>
<pre><code class="language-c"><span class="code-comment">// When we delete a node, we must free its memory to prevent leaks.</span>
<span class="code-function">free</span>(nodeToDelete);</code></pre>
</div>
<div id="level-3" class="container reveal">
<h2>LEVEL 3: NAVIGATING THE LABYRINTH (Linked Lists)</h2>
<p>
A linked list is a chain of `structs` (we call them "nodes"). Each node holds its own data and, crucially, a pointer to the `next` node in the chain. The last node's `next` pointer is `NULL`, signaling the end of the path.
</p>
<h3>Traversal: The Basic Move</h3>
<p>
To walk through the list, you create a temporary pointer (let's call it `current`) and start it at the head of the list. Then, you loop, moving the pointer forward with `current = current->next;` until you hit `NULL`.
</p>
<pre><code class="language-c"><span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* current = list; <span class="code-comment">// Start at the beginning.</span>
<span class="code-keyword">while</span> (current != NULL) {
<span class="code-comment">// Do something with the 'current' node...</span>
current = current->next; <span class="code-comment">// Move to the next node.</span>
}</code></pre>
</div>
<div id="boss-battles" class="container reveal">
<h2>BOSS BATTLES: IMPLEMENTING THE CORE FUNCTIONS</h2>
<p>These are the key functions from your homework. Master them, and you've conquered the level.</p>
<h3 id="countNodes">Mini-Boss: `countNodes()`</h3>
<p>A simple traversal to count every node in the list. This is your warm-up.</p>
<pre><button class="copy-btn">Copy</button><code class="language-c"><span class="code-type">int</span> <span class="code-function">countNodes</span>()
{
<span class="code-type">int</span> count = 0; <span class="code-comment">// Start counter at zero.</span>
<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* current = list; <span class="code-comment">// Temporary pointer to walk the list.</span>
<span class="code-keyword">while</span> (current != NULL) {
count++; <span class="code-comment">// Add one for the current student.</span>
current = current->next; <span class="code-comment">// Move to the next student.</span>
}
<span class="code-keyword">return</span> count; <span class="code-comment">// Return the total.</span>
}</code></pre>
<h3 id="displayList">Mini-Boss: `displayList()`</h3>
<p>Traverse the list and print each student's stats. The key challenge is converting the `schoolYear` enum back to a human-readable string.</p>
<pre><button class="copy-btn">Copy</button><code class="language-c"><span class="code-keyword">void</span> <span class="code-function">displayList</span>()
{
<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* current = list; <span class="code-comment">// Temp pointer to walk the list.</span>
<span class="code-keyword">while</span> (current != NULL) {
<span class="code-function">printf</span>(<span class="code-string">"\nStudent name: %s"</span>, current->studentName);
<span class="code-function">printf</span>(<span class="code-string">"\nStudent major: %s"</span>, current->major);
<span class="code-function">printf</span>(<span class="code-string">"\nID number: %d"</span>, current->IDNumber);
<span class="code-comment">// Use a switch to translate the enum number to a string.</span>
<span class="code-keyword">switch</span> (current->schoolYear) {
<span class="code-keyword">case</span> freshman: <span class="code-function">printf</span>(<span class="code-string">"\nSchoolYear: freshman\n"</span>); <span class="code-keyword">break</span>;
<span class="code-keyword">case</span> sophomore: <span class="code-function">printf</span>(<span class="code-string">"\nSchoolYear: sophomore\n"</span>); <span class="code-keyword">break</span>;
<span class="code-keyword">case</span> junior: <span class="code-function">printf</span>(<span class="code-string">"\nSchoolYear: junior\n"</span>); <span class="code-keyword">break</span>;
<span class="code-keyword">case</span> senior: <span class="code-function">printf</span>(<span class="code-string">"\nSchoolYear: senior\n"</span>); <span class="code-keyword">break</span>;
}
current = current->next; <span class="code-comment">// Move to the next student.</span>
}
}</code></pre>
<h3 id="swapNodes">Helper Mob: `swapNodes()`</h3>
<p>A crucial helper function for sorting. It swaps the *data* inside two nodes but leaves their `next` pointers untouched. This is much more efficient than re-wiring the list structure.</p>
<pre><button class="copy-btn">Copy</button><code class="language-c"><span class="code-keyword">void</span> <span class="code-function">swapNodes</span>(<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* node1, <span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* node2)
{
<span class="code-comment">// We need temporary variables to hold the data from node1 during the swap.</span>
<span class="code-type">char</span> tempName[MAX_NAME_LENGTH];
<span class="code-type">char</span> tempMajor[MAX_NAME_LENGTH];
<span class="code-type">schoolYearType</span> tempSchoolYear;
<span class="code-type">unsigned int</span> tempID;
<span class="code-comment">// Use strcpy for strings and direct assignment for numbers/enums.</span>
<span class="code-function">strcpy</span>(tempName, node1->studentName);
<span class="code-function">strcpy</span>(tempMajor, node1->major);
tempSchoolYear = node1->schoolYear;
tempID = node1->IDNumber;
<span class="code-function">strcpy</span>(node1->studentName, node2->studentName);
<span class="code-function">strcpy</span>(node1->major, node2->major);
node1->schoolYear = node2->schoolYear;
node1->IDNumber = node2->IDNumber;
<span class="code-function">strcpy</span>(node2->studentName, tempName);
<span class="code-function">strcpy</span>(node2->major, tempMajor);
node2->schoolYear = tempSchoolYear;
node2->IDNumber = tempID;
}</code></pre>
<h3 id="deleteNode">Final Boss: `deleteNode()`</h3>
<p>This is where your pointer skills are truly tested. You must find the node, carefully re-wire the `next` pointers to bypass it, and then `free()` its memory. Handling the head of the list is a critical special case!</p>
<pre><button class="copy-btn">Copy</button><code class="language-c"><span class="code-type">int</span> <span class="code-function">deleteNode</span>(<span class="code-type">char</span>* studentName_input)
{
<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* current = list; <span class="code-comment">// To find the node.</span>
<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* previous = NULL; <span class="code-comment">// To keep track of the node before.</span>
<span class="code-comment">// Case 1: The list is empty.</span>
<span class="code-keyword">if</span> (list == NULL) {
<span class="code-keyword">return</span> -1; <span class="code-comment">// Nothing to delete.</span>
}
<span class="code-comment">// Case 2: The head node is the one to delete.</span>
<span class="code-keyword">if</span> (<span class="code-function">strcmp</span>(list->studentName, studentName_input) == 0) {
current = list; <span class="code-comment">// Mark the head for deletion.</span>
list = list->next; <span class="code-comment">// The second node is now the new head.</span>
<span class="code-function">free</span>(current); <span class="code-comment">// Banish the old head!</span>
<span class="code-keyword">return</span> 1; <span class="code-comment">// Success!</span>
}
<span class="code-comment">// Case 3: Search the rest of the list.</span>
<span class="code-keyword">while</span> (current != NULL && <span class="code-function">strcmp</span>(current->studentName, studentName_input) != 0) {
previous = current; <span class="code-comment">// Move 'previous' to where 'current' is.</span>
current = current->next; <span class="code-comment">// Move 'current' one step forward.</span>
}
<span class="code-comment">// If we finished the loop and 'current' is NULL, the student wasn't found.</span>
<span class="code-keyword">if</span> (current == NULL) {
<span class="code-keyword">return</span> 0; <span class="code-comment">// Not found.</span>
}
<span class="code-keyword">else</span> { <span class="code-comment">// We found the node at 'current'.</span>
<span class="code-comment">// Stitch the list: make the previous node's 'next' skip over 'current'.</span>
previous->next = current->next;
<span class="code-function">free</span>(current); <span class="code-comment">// Banish the found node.</span>
<span class="code-keyword">return</span> 1; <span class="code-comment">// Success!</span>
}
}</code></pre>
</div>
<div id="final-code" class="container reveal">
<h2>TREASURE ROOM: THE COMPLETE `addSort()` FUNCTION</h2>
<p>This is the final challenge, combining all your skills: duplicate checking, memory allocation, appending to the list, and finally, sorting the list using a Bubble Sort and your `swapNodes` helper. This is the complete solution to Q1.</p>
<pre><button class="copy-btn">Copy</button><code class="language-c"><span class="code-type">int</span> <span class="code-function">addSort</span>(<span class="code-type">char</span>* studentName_input, <span class="code-type">char</span>* major_input, <span class="code-type">char</span>* schoolYear_input, <span class="code-type">unsigned int</span> IDNumber_input)
{
<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* current = list;
<span class="code-comment">// 1. Check for Duplicates</span>
<span class="code-keyword">while</span>(current != NULL){
<span class="code-keyword">if</span>(<span class="code-function">strcmp</span>(current->studentName, studentName_input) == 0){
<span class="code-keyword">return</span> 0; <span class="code-comment">// Found a duplicate, fail.</span>
}
current = current->next;
}
<span class="code-comment">// 2. Create New Node</span>
<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* newNode = (<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>*)<span class="code-function">malloc</span>(<span class="code-keyword">sizeof</span>(<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>));
<span class="code-function">strcpy</span>(newNode->studentName, studentName_input);
<span class="code-function">strcpy</span>(newNode->major, major_input);
newNode->IDNumber = IDNumber_input;
newNode->next = NULL;
<span class="code-keyword">if</span> (<span class="code-function">strcmp</span>(schoolYear_input, <span class="code-string">"freshman"</span>) == 0) newNode->schoolYear = freshman;
<span class="code-keyword">else if</span> (<span class="code-function">strcmp</span>(schoolYear_input, <span class="code-string">"sophomore"</span>) == 0) newNode->schoolYear = sophomore;
<span class="code-keyword">else if</span> (<span class="code-function">strcmp</span>(schoolYear_input, <span class="code-string">"junior"</span>) == 0) newNode->schoolYear = junior;
<span class="code-keyword">else if</span> (<span class="code-function">strcmp</span>(schoolYear_input, <span class="code-string">"senior"</span>) == 0) newNode->schoolYear = senior;
<span class="code-comment">// 3. Append Node to List</span>
<span class="code-keyword">if</span> (list == NULL) {
list = newNode;
} <span class="code-keyword">else</span> {
current = list;
<span class="code-keyword">while</span> (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
<span class="code-comment">// 4. Sort The List (Bubble Sort)</span>
<span class="code-type">int</span> swapped;
<span class="code-keyword">struct</span> <span class="code-type">studentRecord</span>* ptr1;
<span class="code-keyword">if</span> (list == NULL || list->next == NULL) {
<span class="code-keyword">return</span> 1; <span class="code-comment">// Already sorted.</span>
}
<span class="code-keyword">do</span> {
swapped = 0;
ptr1 = list;
<span class="code-keyword">while</span> (ptr1->next != NULL) {
<span class="code-keyword">if</span> (<span class="code-function">strcmp</span>(ptr1->studentName, ptr1->next->studentName) > 0) {
<span class="code-function">swapNodes</span>(ptr1, ptr1->next);
swapped = 1;
}
ptr1 = ptr1->next;
}
} <span class="code-keyword">while</span> (swapped);
<span class="code-keyword">return</span> 1; <span class="code-comment">// Success!</span>
}</code></pre>
</div>
</main>
<footer>
<p>MISSION COMPLETE!</p>
<p>You have conquered the Linked List Labyrinth.</p>
</footer>
<script>
// Smooth scrolling for navigation links
document.querySelectorAll('nav a').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
});
});
// Add copy functionality to all copy buttons
document.querySelectorAll('.copy-btn').forEach(button => {
button.addEventListener('click', () => {
const pre = button.parentElement;
const code = pre.querySelector('code');
const text = code.innerText;
const textArea = document.createElement('textarea');
textArea.value = text;
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand('copy');
button.innerText = 'Copied!';
} catch (err) {
console.error('Failed to copy text: ', err);
button.innerText = 'Error!';
}
document.body.removeChild(textArea);
setTimeout(() => {
button.innerText = 'Copy';
}, 2000);
});
});
// Scroll reveal animation
const revealElements = document.querySelectorAll('.reveal');
const revealObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('active');
}
});
}, { threshold: 0.1 });
revealElements.forEach(el => {
revealObserver.observe(el);
});
</script>
</body>
</html>