Skip to content

Shell Sort with Sedgewick Gaps

Shell sort using Sedgewick gap sequence for improved practical performance.

Shell sort with Sedgewick gaps uses a carefully designed sequence that improves both theoretical and practical performance over earlier sequences such as Shell and Hibbard.

Two common Sedgewick sequences are used in practice. A widely cited version is:

gk={92k92k/2+1if k even 82k62(k+1)/2+1if k odd g_k = \begin{cases} 9 \cdot 2^k - 9 \cdot 2^{k/2} + 1 & \text{if } k \text{ even} \ 8 \cdot 2^k - 6 \cdot 2^{(k+1)/2} + 1 & \text{if } k \text{ odd} \end{cases}

This produces gaps such as:

1,5,19,41,109, 1, 5, 19, 41, 109, \dots

You use all values less than nn, in decreasing order.

Problem

Given a sequence AA of length nn, reorder it such that

A[0]A[1]A[n1] A[0] \le A[1] \le \cdots \le A[n-1]

Gap Sequence

Generate all Sedgewick gaps less than nn, then apply them in descending order.

Example for n=50n = 50:

41,19,5,1 41, 19, 5, 1

Algorithm

For each gap, perform insertion sort on elements spaced by that gap.

shell_sort_sedgewick(A):
    n = length(A)

    gaps = generate_sedgewick_gaps(n)

    for gap in reverse(gaps):
        for i from gap to n - 1:
            key = A[i]
            j = i

            while j >= gap and A[j - gap] > key:
                A[j] = A[j - gap]
                j = j - gap

            A[j] = key

Example

Let

A=[9,8,3,7,5,6,4,1] A = [9, 8, 3, 7, 5, 6, 4, 1]

For n=8n = 8, Sedgewick gaps are:

5,1 5, 1

Gap 5:

→ reduces long-distance inversions

Gap 1:

→ final insertion sort

Result:

[1,3,4,5,6,7,8,9] [1, 3, 4, 5, 6, 7, 8, 9]

Correctness

Each gap enforces ordering among elements spaced by that gap. As gaps decrease, the array becomes increasingly structured. The final pass with gap 1 ensures full sorting.

Complexity

casetime
worstabout O(n4/3)O(n^{4/3})
averageclose to O(n4/3)O(n^{4/3})
bestO(nlogn)O(n \log n)

Space complexity:

O(1) O(1)

Properties

  • in-place
  • not stable
  • strong practical performance
  • widely used in tuned Shell sort implementations

When to Use

Sedgewick gaps are preferred when using Shell sort in practice. They offer a good balance between simplicity and performance without requiring complex tuning.

Implementation

def sedgewick_gaps(n):
    gaps = []
    k = 0
    while True:
        if k % 2 == 0:
            gap = 9 * (2**k) - 9 * (2**(k//2)) + 1
        else:
            gap = 8 * (2**k) - 6 * (2**((k+1)//2)) + 1
        if gap >= n:
            break
        gaps.append(gap)
        k += 1
    return gaps

def shell_sort_sedgewick(a):
    n = len(a)
    gaps = sedgewick_gaps(n)

    for gap in reversed(gaps):
        for i in range(gap, n):
            key = a[i]
            j = i

            while j >= gap and a[j - gap] > key:
                a[j] = a[j - gap]
                j -= gap

            a[j] = key

    return a
func SedgewickGaps(n int) []int {
    gaps := []int{}
    for k := 0; ; k++ {
        var gap int
        if k%2 == 0 {
            gap = 9*(1<<k) - 9*(1<<(k/2)) + 1
        } else {
            gap = 8*(1<<k) - 6*(1<<((k+1)/2)) + 1
        }
        if gap >= n {
            break
        }
        gaps = append(gaps, gap)
    }
    return gaps
}

func ShellSortSedgewick[T constraints.Ordered](a []T) {
    gaps := SedgewickGaps(len(a))

    for g := len(gaps) - 1; g >= 0; g-- {
        gap := gaps[g]
        for i := gap; i < len(a); i++ {
            key := a[i]
            j := i

            for j >= gap && a[j-gap] > key {
                a[j] = a[j-gap]
                j -= gap
            }

            a[j] = key
        }
    }
}