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
160: Whiteboard Practice: Reversing a Linked List
If you've ever sat through a technical interview, you know that reversing a linked list is practically a rite of passage. It's not because it's the most common task in a production environment—you'll likely use a built-in collection for that—but because it tests whether you can visualize pointers moving in your head without getting lost.
Imagine a line of people standing in a room. Each person has their hand on the shoulder of the person in front of them. Person A is holding B, B is holding C, and so on. Now, I want you to reverse that line so that C is holding B, and B is holding A. Here is the catch: you can't just tell everyone to turn around at once, and you can't let go of the chain entirely, or you'll lose track of where the people are in the room.
To do this, you have to go person by person. You tell Person B, "Before you let go of Person C, remember where they are. Now, instead of holding C, reach back and hold Person A." But Person B can only do that if someone is keeping track of who Person A is. You need a "current" person, a "previous" person, and a "next" person to make sure the chain doesn't snap.
Mapping the Chain to C#
In C#, the "hand on the shoulder" is just a reference to the next ListNode object. To reverse the list, we need three pointers to keep track of our position as we iterate. Here is how the analogy translates to the code:
- Previous (The person behind): This starts as
nullbecause the original head will become the new tail. - Current (The person we are talking to): This starts at the head of the list.
- Next (The safety grip): This is a temporary variable we use to hold the reference to the rest of the list before we break the link.
public class ListNode {
public int Value;
public ListNode Next;
public ListNode(int val = 0, ListNode next = null) {
this.Value = val;
this.Next = next;
}
}
public class LinkedListLogic {
public ListNode ReverseList(ListNode head) {
ListNode prev = null;
ListNode current = head;
while (current != null) {
// 1. Save the next node (the 'safety grip')
ListNode nextTemp = current.Next;
// 2. Reverse the pointer (the 'flip')
current.Next = prev;
// 3. Move prev and current forward one step
prev = current;
current = nextTemp;
}
// At the end, current is null and prev is the new head
return prev;
}
}
The Mental Loop
The most important part of this logic is the order of operations inside that while loop. If you flip the pointer (current.Next = prev) before you save the next node (nextTemp = current.Next), you've just cut the chain. You'll have no way to get to the rest of the list, and your program will just stop or crash.
I always tell my juniors to visualize this as a "slide." You slide nextTemp forward, then you flip the current arrow backward, then you slide prev and current forward. It's a rhythmic movement. If you get the rhythm wrong, the whole thing falls apart.
Handling the Edge Cases
One thing that often trips people up on a whiteboard is the "empty list" or "single item list" scenario. The beauty of the while (current != null) approach is that it handles these naturally. If the list is empty, current is null immediately, the loop never runs, and it returns prev (which is also null). If there's only one node, it flips that node to point to null and returns it. No special if statements are required, which makes the code much cleaner.
📋 Practical Task
Exercise: Implement the Singly Linked List Reversal Logic
Below is a partial implementation of a LinkedListReverser class. Your task is to complete the Reverse method. The method must take the head of a singly linked list and return the new head of the reversed list without using any extra data structures (like a Stack or a List) to store the nodes.
public class ListNode {
public int Value;
public ListNode Next;
public ListNode(int val = 0, ListNode next = null) {
this.Value = val;
this.Next = next;
}
}
public class LinkedListReverser {
public ListNode Reverse(ListNode head) {
// TODO: Implement the reversal logic here
// 1. Initialize prev and current pointers
// 2. Iterate through the list, flipping the Next references
// 3. Return the new head of the reversed list
}
}
// Test case for your implementation:
// Input: 1 -> 2 -> 3 -> 4 -> 5 -> null
// Expected Output: 5 -> 4 -> 3 -> 2 -> 1 -> null
There are no comments for now.