function shellSort(array: number[]) { for (let gap = Math.floor(array.length / 2); gap > 0; gap = Math.floor(gap / 2)) { for (let i = gap; i < array.length; i++) {const key = array[i];
let j = i;
while (j >= gap && array[j - gap] > key) {array[j] = array[j - gap];
j -= gap;
}
array[j] = key;
}
}
}
Gap 12: insertion sort every subsequence of elements 12 apart.
Understanding Shell sort
The idea
Shell sort runs insertion sort on subsequences of elements a fixed gap apart, then shrinks the gap and repeats, ending with gap 1, which is plain insertion sort. Each coarse pass moves elements long distances cheaply, so by the final pass every element is close to its place and insertion sort runs near its linear best case.
The gap sequence decides the running time. Halving, as here, gives O(n²) in the worst case but O(n^1.5) typically; sequences like Ciura's 1, 4, 10, 23, 57, 132, … do measurably better, and the true complexity of the best sequence is still an open problem.
The four stages
Complexity
Versus its siblings
Pseudocode
SHELLSORT(array)
for gap ← ⌊n/2⌋, ⌊n/4⌋, …, 1
for i ← gap to n − 1
key ← array[i]; j ← i
while j ≥ gap and array[j − gap] > key: array[j] ← array[j − gap]; j ← j − gap
array[j] ← key
When to use
Pitfalls
History
Donald Shell published it in 1959, the first sort to break the O(n²) barrier in practice. The analysis has occupied Knuth, Pratt, Sedgewick and others for sixty years; Pratt proved O(n log² n) for the 2ᵖ3ᵠ sequence in 1971, and the gap sequence question remains open.