Skip to content

Insertion sort

Problem

Implement stable insertion sort for Python lists and singly linked lists.

Key trick

Maintain a sorted prefix and insert each new element into its correct position.

Both versions take \(O(n^2)\) time in the worst case and \(O(1)\) auxiliary space.

Trap

For stability, insert a new equal element after existing equal elements.

Why is it interesting?

It is excellent for small or nearly sorted inputs and works naturally by relinking linked-list nodes.

Python solution

Python list

class sort_insertion_sort:
    def sort(self, nums: list[int]) -> list[int]:
        # Preserve the caller's input.
        arr = nums[:]

        # `arr[:i]` is the sorted prefix.
        for i in range(1, len(arr)):
            val = arr[i]
            j = i - 1

            # Shift larger elements right to open an insertion position.
            # Using `>` rather than `>=` preserves the order of equal values.
            while j >= 0 and arr[j] > val:
                arr[j + 1] = arr[j]
                j -= 1

            # Insert the saved value into the resulting gap.
            arr[j + 1] = val

        return arr

Singly linked list

class sort_insertion_sort_linked:
    def sort(
        self,
        head: ListNode | None,
    ) -> ListNode | None:
        # `dummy.next` is the head of the independently built sorted list.
        dummy = ListNode()
        cur = head

        while cur:
            # Save the next unsorted node before changing `cur.next`.
            nxt = cur.next

            # Find the node after which `cur` should be inserted.
            prev = dummy

            # Move past equal values to preserve their original order.
            while prev.next and prev.next.val <= cur.val:
                prev = prev.next

            # Insert `cur` between `prev` and `prev.next`.
            cur.next = prev.next
            prev.next = cur

            cur = nxt

        return dummy.next