Reverse a doubly linked list

How can you reverse a double linked list?

2026 Update: Reversing a Doubly Linked List — Full Implementation

Reversing a doubly linked list requires swapping both next and prev pointers for every node. It’s simpler than singly-linked reversal but tests understanding of pointer manipulation.

class DLLNode:
    def __init__(self, val=0, prev=None, next=None):
        self.val = val
        self.prev = prev
        self.next = next

def reverse_doubly_linked_list(head: DLLNode) -> DLLNode:
    """
    Reverse a doubly linked list in-place.
    Returns the new head (old tail).
    Time: O(n), Space: O(1)
    """
    if not head or not head.next:
        return head

    curr = head
    new_head = None

    while curr:
        # Swap prev and next pointers
        curr.prev, curr.next = curr.next, curr.prev
        new_head = curr
        # Move to the original next (now stored in curr.prev after swap)
        curr = curr.prev

    return new_head

# Helper functions for testing
def build_dll(values: list) -> DLLNode:
    if not values:
        return None
    head = DLLNode(values[0])
    curr = head
    for val in values[1:]:
        node = DLLNode(val, prev=curr)
        curr.next = node
        curr = node
    return head

def dll_to_list(head: DLLNode) -> list:
    result = []
    curr = head
    while curr:
        result.append(curr.val)
        curr = curr.next
    return result

def verify_prev_pointers(head: DLLNode) -> bool:
    """Verify all prev pointers are correct after reversal."""
    curr = head
    while curr and curr.next:
        if curr.next.prev != curr:
            return False
        curr = curr.next
    return True

# Test
head = build_dll([1, 2, 3, 4, 5])
print(dll_to_list(head))   # [1, 2, 3, 4, 5]

new_head = reverse_doubly_linked_list(head)
print(dll_to_list(new_head))   # [5, 4, 3, 2, 1]
print(verify_prev_pointers(new_head))  # True

# Compare with singly linked list reversal
class SLLNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def reverse_singly(head: SLLNode) -> SLLNode:
    prev = None
    curr = head
    while curr:
        next_node = curr.next
        curr.next = prev
        prev = curr
        curr = next_node
    return prev

Key differences DLL vs SLL reversal:

  • DLL: swap both prev and next — one statement curr.prev, curr.next = curr.next, curr.prev
  • SLL: only update next, need temporary variable to not lose forward pointer
  • Both: O(n) time, O(1) space, single pass

Follow-up: Reverse k nodes at a time in DLL: More complex — need to preserve the outer prev and next links of each group. LeetCode #25 (Reverse Nodes in k-Group) for singly linked lists; the DLL version requires also fixing the group boundary prev pointers.

💡Strategies for Solving This Problem

The Swap Pattern

Got this at Meta. It's simpler than reversing a singly linked list in some ways - you have both prev and next pointers to work with.

The Problem

Reverse the direction of all pointers in a doubly linked list. What was next becomes prev, what was prev becomes next.

Example:

Original: 1 <-> 2 <-> 3 <-> 4
Reversed: 4 <-> 3 <-> 2 <-> 1

Key Insight

For each node, swap its prev and next pointers. That's it. No need to track previous node like in singly linked list.

The Algorithm

  1. Start at head
  2. For each node: swap node.prev and node.next
  3. Move to next node (which is now in node.prev!)
  4. Return what was the last node (now the new head)

O(n) time, O(1) space. Single pass through the list.

The Tricky Part

After swapping pointers, "next" is now in the prev field. You need to move to node.prev to go forward. This confuses people.

Alternative: Three Pointer Approach

Keep track of prev, current, and next. Similar to singly linked list reversal but swap both directions. More verbose but maybe clearer.

At Meta

My interviewer asked "How is this different from reversing a singly linked list?" The key difference: you don't need to track the previous node separately because each node already has a prev pointer.

Then asked about edge cases: empty list, single node, two nodes. All work with the same code.

Scroll to Top