I. What is a Singly Linked List?¶
Before diving in, we need to understand the basic structure of a singly linked list. A singly linked list is a common data structure composed of multiple nodes. Each node contains two parts: a data field (stores data) and a pointer field (stores the address of the next node, typically denoted as next in Python). The first node of the list is called the “head node,” and the pointer field of the last node usually points to None (indicating the end of the list).
For example, a simple singly linked list can be represented as: 1 -> 2 -> 3 -> None, where 1 is the head node, and each arrow represents the direction of the next pointer.
II. Why Reverse a Linked List?¶
Reversing a linked list is a common operation used in scenarios like:
- Requiring reverse-order output of list data (e.g., printing the list from tail to head).
- Solving algorithmic problems (e.g., checking a palindrome linked list, handling lower digits first in “add two numbers”).
- Optimizing linked list operations (e.g., making certain repeated operations easier after reversal).
III. Iterative Reversal of a Singly Linked List (Recommended for Beginners)¶
Core Idea¶
The iterative approach revolves around traversing the list and reversing the pointer direction of each node one by one. We maintain three pointers: prev (previous node), current (current node), and next (next node). By cyclically moving these pointers, we gradually reverse each node’s next pointer from pointing to the next node to pointing to the previous node.
Step-by-Step Explanation¶
- Initialize Pointers: Set
prevtoNone(the end of the reversed list) andcurrentto the head nodehead. - Traverse the List: While
currentis notNone, perform the following:
- Savecurrent.next(the next node) to thenextvariable (to avoid losing subsequent nodes after pointer reversal).
- Reverse thenextpointer ofcurrentto point toprev.
- Moveprevtocurrent(makingprevthe new “previous node”).
- Movecurrenttonext(makingcurrentthe new “current node”). - Termination: When
currentisNone,prevbecomes the head node of the reversed list.
Example Walkthrough (1->2->3->None)¶
Let’s take the linked list 1 -> 2 -> 3 -> None and walk through the reversal step by step:
- Initial State:
prev = None,current = 1,next = ? - First Iteration:
- Save
next = current.next = 2; - Reverse
current.nexttoprev = None(list becomes1 -> None); - Update
prev = current = 1; - Update
current = next = 2. - Second Iteration:
- Save
next = current.next = 3; - Reverse
current.nexttoprev = 1(list becomes2 -> 1 -> None); - Update
prev = current = 2; - Update
current = next = 3. - Third Iteration:
- Save
next = current.next = None; - Reverse
current.nexttoprev = 2(list becomes3 -> 2 -> 1 -> None); - Update
prev = current = 3; - Update
current = next = None. - Termination:
currentisNone, so reversal is complete. The new head node isprev = 3.
Python Implementation¶
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverse_iterative(head):
prev = None
current = head
while current is not None:
next_node = current.next # Save the next node
current.next = prev # Reverse current node's pointer
prev = current # Move prev forward
current = next_node # Move current forward
return prev # prev is now the new head
IV. Recursive Reversal of a Singly Linked List (Understanding Recursion)¶
Core Idea¶
The recursive approach leverages the idea of first reversing the sublist after the current node, then attaching the current node to the end of the reversed sublist. The key is decomposing the problem into smaller subproblems and clarifying the base case and recursive step.
Key Concepts¶
- Base Case: If the list is empty (
head is None) or has only one node (head.next is None), return the original head node (no reversal needed). - Recursive Step:
- Recursively callreverse(head.next)to get the head node of the reversed sublist (new_head).
- Reverse the pointer of the current nodehead(originally pointing to the sublist head) to point to the previous node (the end of the reversed sublist).
- Set thenextpointer ofheadtoNone(making it the new tail node).
- Returnnew_head(the head of the reversed sublist).
Example Walkthrough (1->2->3->None)¶
Using the linked list 1 -> 2 -> 3 -> None, let’s trace the recursion:
- Initial Call:
reverse(1) - Recursively call
reverse(2), which returnsnew_head = 3(reversed sublist:3 -> 2 -> None). - Modify the current node
1: Sethead.next.next = head(i.e.,2.next = 1). - Set
head.next = None(making1the new tail). - Return
new_head = 3, resulting in the reversed list:3 -> 2 -> 1 -> None.
Python Implementation¶
def reverse_recursive(head):
# Base case: empty list or single node
if head is None or head.next is None:
return head
# Recursively reverse the sublist starting from head.next
new_head = reverse_recursive(head.next)
# Attach current node to the end of the reversed sublist
head.next.next = head
# Mark current node as the new tail
head.next = None
return new_head # Return the head of the reversed sublist
V. Summary¶
Comparison of Methods¶
| Method | Time Complexity | Space Complexity | Key Traits |
|---|---|---|---|
| Iterative | O(n) | O(1) | Intuitive, no stack overflow |
| Recursive | O(n) | O(n) | Concise, but relies on recursion stack |
Key Takeaways¶
- Iterative Approach: Critical to maintain pointer order (save
nextfirst, reverse, then move pointers). - Recursive Approach: Requires clear base cases (empty/single node) and understanding how to attach the current node to the reversed sublist.
By mastering both methods, you’ll grasp the core concepts of linked list reversal. The iterative method is ideal for beginners to understand pointer manipulation, while recursion helps solidify recursive thinking in linked list problems. Practice visualizing pointer movements to master the logic!