How do you reverse a singly linked list in place?
You need three pointers: the node you are currently on, the node you have already processed, and the node that is coming next. At each step you save the next node, point the current node backwards at the previous one, and then advance. The head of the reversed list is the last node you process.
class Node:
def __init__(self, value, next_node=None):
self.value = value
self.next = next_node
def build(values):
head = None
for value in reversed(values):
head = Node(value, head)
return head
def to_list(head):
out = []
while head:
out.append(head.value)
head = head.next
return out
def reverse(head):
previous = None
current = head
while current:
following = current.next
current.next = previous
previous = current
current = following
return previous
print(to_list(build([1, 2, 3, 4, 5])))
print(to_list(reverse(build([1, 2, 3, 4, 5]))))The outputs are 1, 2, 3, 4, 5 and 5, 4, 3, 2, 1. The list itself is reversed in place, so no new nodes are allocated and the original list object is the one being changed.
The mechanism is that saving the next pointer before overwriting it is what keeps the rest of the list reachable. Without that save, the moment you set the current node's next to the previous node you lose the remainder of the list. The invariant that holds throughout is that previous points at the reversed prefix and current points at the first node of the untouched suffix.
The trade-off to name is the dummy head problem. The iterative version returns the new head explicitly, which means the caller has to use the return value rather than trusting the argument. A version that installs a dummy node before the real head avoids that, at the cost of one extra node. Both are O of n time and O of 1 space, and the iterative version is preferable whenever the list is long, because the recursive version in the next answer uses stack space proportional to the length and will overflow on a very long list.