Smoothsort

Smoothsort is an $$O(n \log n)$$ algorithm, although it is adaptive with a best case of $$O(n)$$. It is not stable, and uses $$O(\log n)$$ memory.

= Explanation = Note: if you haven't read Heapsort, read it now. it provides the concepts for smoothsort.

Why Heapsort isn't adaptive
Smoothsort is basically heapsort, so why isn't heapsort adaptive?

It's because, heapsort's heaps are guaranteed to have the max-element at the front, but to get that element to the end, you have to swap it with a random element of the heap and sink that element. That's the killer step, because it is almost certainly going to take $$O(\log n)$$ time. We need to derive a data structure that eliminates this problem. So instead of putting the max element at the start, far away from where it should be, why don't we put it at the end?

This idea has a problem, though. if we use regular max-heaps, then when we get rid of the max element (no swapping because it's already at the end), we crack the heap in two, and the only way to uncrack it is to swap something and sink it. that won't do, because that will be $$O(\log n)$$. so, we need a structure that can be cracked in two without a problem.

So, instead of using one heap, what if we used a forest of heaps?

Leonardo Heaps and Trees
Leonardo heaps (as opposed to regular heaps) are based on the concept of Leonardo numbers. A Leonardo number $$L(n)$$ is defined as follows: $$L(1)$$ and $$L(0)$$ are 1. Otherwise, $$L(n)$$ = $$L(n - 2) + L(n - 1) + 1$$.

A Leonardo tree is defined similarly: A tree of order 0 or 1 are single nodes. Otherwise, they are a node with the Leonardo tree of the orders n - 1 and n - 2 as children. Leonardo trees must follow the heap property: that is, each node must be larger than its children.

Leonardo heaps are a forest of Leonardo trees arranged in such a way that the orders of the trees are sorted in descending order (no duplicate orders), and the roots of the trees are sorted in ascending order (that is, the tree with the largest root must be at the end). Now this structure allows us to efficiently remove the maximum (we can just crack the leftmost heap in two). But there's a problem.

How do we even build this thing in the first place?

Heap operations
We already know the insert and delete-max operations on regular heaps, but on smooth heaps they will be very different.

Insertion
To insert an item into a Leonardo heap, first check if the last two trees (the ones with the smallest orders) have sizes corresponding to the numbers $$L(n - 1)$$ and $$L(n - 2)$$. if so, simply make both trees the children of the new item. If not, check the order of the last tree. if it is 1, insert the item as a tree of order 0. otherwise, insert the item as a tree of order 1.

Now, to validate the property that the roots must be sorted, we insertion-sort the new root to its correct place, but with the added rule that the root should only be swapped with the previous one if the previous root is larger than both the root's children. Finally we do a regular sink operation in whichever tree the new root ended up in.