C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
119: Implementing a Linked List in C#
I've always found that the best way to understand linked lists isn't by looking at a diagram of boxes and arrows, but by feeling the pain of the alternative. Let's imagine we're building a music playlist manager. We want to be able to add songs, remove them, and move them around without rewriting the entire list every time.
The Wall we hit with Arrays
If we used a standard array or even a List<T> under the hood, adding a song to the middle of a 10,000-song playlist is actually an expensive operation. The computer has to shift every single subsequent element one slot to the right to make room. It's a lot of unnecessary copying. I tried doing this in a prototype earlier, and while it's fast for small lists, the memory shuffling is just inefficient for a structure that's meant to be fluid.
So, what if we didn't store everything in one contiguous block of memory? What if each song just knew who the next song was?
Building the Atomic Unit: The Node
Let's try to define a "Node." Think of this as a wrapper. It doesn't just hold the song data; it holds a pointer to another node of the same type. I'll start with something simple:
public class SongNode
{
public string SongTitle { get; set; }
public SongNode Next { get; set; }
public SongNode(string title)
{
SongTitle = title;
Next = null; // By default, it's the end of the line
}
}
Now, if I just create a few of these in a Main method, I can manually link them. node1.Next = node2; node2.Next = node3;. It works, but it's tedious. If I lose the reference to node1, I've effectively lost the entire playlist because I have no way to get back to the start. That's a disaster waiting to happen. We need a manager class.
Creating the Playlist Manager
I'll create a Playlist class. Its only real job is to keep track of where the list starts—the "Head." As long as I have the head, I can follow the Next chain to find anything else.
public class Playlist
{
private SongNode head;
public void PrintPlaylist()
{
SongNode current = head;
while (current != null)
{
Console.WriteLine(current.SongTitle);
current = current.Next;
}
}
}
Wait, I just realized I can't actually add anything to this yet. If I just create a Add(string title) method and set head = new SongNode(title), I'll just be overwriting the start of my list every time. I need to append to the end.
The Logic of Traversing
To add a song to the end, I have to start at the head and "walk" down the chain until I find a node where Next is null. That's the current end. Then I just plug my new song in there.
Let's try to implement that. I'll run into a problem immediately: what if the list is empty? If head is null, I can't walk down a chain that doesn't exist. I'll need a guard clause for that.
public void AddSong(string title)
{
SongNode newNode = new SongNode(title);
if (head == null)
{
head = newNode;
return;
}
SongNode current = head;
while (current.Next != null)
{
current = current.Next;
}
current.Next = newNode;
}
Now it's working. I can add "Bohemian Rhapsody," then "Stairway to Heaven," and the PrintPlaylist method will follow the trail. The beauty here is that if I want to insert a song in the middle, I don't have to shift 1,000 elements. I just find the node before the insertion point, point its Next to my new node, and point the new node's Next to the rest of the chain. It's like unhooking two train cars and snapping a new one in between them.
📋 Practical Task
Exercise: Implementing the "Remove Song" Feature
Your playlist manager is almost complete, but it's missing a way to delete songs. Your task is to add a method called RemoveSong(string title) to the Playlist class.
Requirements:
- The method should search for a song by its title.
- If the song to be removed is the
head, theheadshould be updated to the second node in the list. - If the song is in the middle or at the end, you must "skip" it by connecting the node before the target to the node after the target.
- If the song isn't found, the list should remain unchanged.
Starter Code:
public class SongNode
{
public string SongTitle { get; set; }
public SongNode Next { get; set; }
public SongNode(string title) { SongTitle = title; Next = null; }
}
public class Playlist
{
private SongNode head;
public void AddSong(string title)
{
SongNode newNode = new SongNode(title);
if (head == null) { head = newNode; return; }
SongNode current = head;
while (current.Next != null) { current = current.Next; }
current.Next = newNode;
}
// TODO: Implement RemoveSong(string title) here
public void PrintPlaylist()
{
SongNode current = head;
while (current != null)
{
Console.WriteLine(current.SongTitle);
current = current.Next;
}
}
}
There are no comments for now.