Skip to content

Top-down merge sort linked list

Problem

Implement recursive merge sort for a linked list.

Key trick

Recursively split the input into halves, then stably merge the sorted halves.

Trap

Choose from the left on equality for stability; linked lists also use \(O(\log n)\) recursion space.

Why is it interesting?

It guarantees stable \(O(n \log n)\) sorting and works especially well with linked lists.

Python solution

class sorting_merge_sort_top_down_linked_list:
    def sort(
        self,
        head: ListNode | None,
    ) -> ListNode | None:
        # Empty and one-node lists are already sorted.
        if head is None or head.next is None:
            return head

        # Find the midpoint with the slow/fast-pointer pattern.
        # Starting `fast` one node ahead leaves `slow` at the end
        # of the left half.
        slow = head
        fast = head.next

        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next

        # Split the list into two independent lists.
        r = slow.next
        slow.next = None

        # Sort each half and merge their nodes.
        l = self.sort(head)
        r = self.sort(r)

        return self._merge_linked(l, r)

    def _merge_linked(
        self,
        l: ListNode | None,
        r: ListNode | None,
    ) -> ListNode | None:
        # The dummy node removes special handling for the result's head.
        dummy = ListNode()
        tail = dummy

        while l and r:
            # Take from the left on equality to preserve stability.
            if l.val <= r.val:
                tail.next = l
                l = l.next
            else:
                tail.next = r
                r = r.next

            tail = tail.next

        # The remaining list is already sorted, so attach it directly.
        tail.next = l if l else r

        return dummy.next