Sort in place with a heap-like structure that keeps worst-case O(n log n) time while approaching linear time on nearly sorted input.
Smoothsort is an adaptive heap-based sorting algorithm. It preserves the in-place and worst-case guarantees of heapsort, but it performs much less work when the input is already close to sorted.
You use it when constant extra space matters and the input may contain existing order.
Problem
Given an array ( A ) of length ( n ), sort it in place while taking advantage of nearly sorted input.
The goal is to achieve:
- worst-case ( O(n \log n) ) time
- near-linear behavior on nearly sorted data
- ( O(1) ) extra space
Idea
Smoothsort uses a forest of Leonardo heaps instead of one binary heap. Leonardo heaps have sizes based on Leonardo numbers:
[ L(0) = 1,\quad L(1) = 1,\quad L(k) = L(k-1) + L(k-2) + 1 ]
These heap sizes allow the algorithm to represent prefixes compactly and merge or split heap structures efficiently.
Algorithm
At a high level:
- Build a forest of Leonardo heaps over the array
- Maintain heap order inside each heap
- Repeatedly remove the maximum element from the forest
- Split Leonardo heaps as needed during extraction
smoothsort(A):
forest = empty_leonardo_forest()
for i in 0..length(A)-1:
add A[i] to forest
restore_heap_order(forest)
for end in length(A)-1 down to 1:
move_max_to_position(A, forest, end)
split_or_shrink_forest(forest)
restore_heap_order(forest)
return AExample
Input:
[ [1, 2, 3, 5, 4] ]
The array is almost sorted. Smoothsort can preserve much of the existing order while performing fewer repairs than ordinary heapsort.
Output:
[ [1, 2, 3, 4, 5] ]
Correctness
Smoothsort maintains a forest of heap-ordered Leonardo trees. The maximum element among the active prefix can be identified from the roots. Moving that maximum to the end places it in its final sorted position.
After each extraction, the remaining prefix is restored into valid heap-ordered Leonardo trees. Repeating this process sorts the whole array.
Complexity
| case | time |
|---|---|
| best, already sorted or nearly sorted | close to ( O(n) ) |
| average | ( O(n \log n) ) |
| worst | ( O(n \log n) ) |
Space:
[ O(1) ]
Comparison with Heapsort
| property | heapsort | smoothsort |
|---|---|---|
| worst-case time | ( O(n \log n) ) | ( O(n \log n) ) |
| nearly sorted input | still ( O(n \log n) ) | close to ( O(n) ) |
| extra space | ( O(1) ) | ( O(1) ) |
| implementation | simple | complex |
| stable | no | no |
When to Use
Use smoothsort when:
- worst-case ( O(n \log n) ) time is required
- extra memory must remain constant
- input is often nearly sorted
- implementation complexity is acceptable
It is mainly useful as a theoretical and systems-level adaptive in-place sort.