Since the Shell sort makes frequent non-sequential accesses to elements of the data structure, only a (destructive) vector version is offered here.
The body of the Shell sort is a nested loop. The outer loop controls the size of the gap, which must decrease monotonically to 1 for the sort to work; Robert Sedgewick's Algorithms recommends gap sizes in the series 1, 4, 13, 40, 121, ..., in which each term is thrice its predecessor plus one. The inner loop then runs through the positions in the vector, effecting a mini-insertion sort on the subsequences of the vector consisting of positions differing by multiples of the gap.
The internally defined insert!
procedure differs from the one
used in the insertion sort in that only positions separated by some
multiple of the specified gap are considered; otherwise the algorithm is
identical.
The computation of the initial gap size is performed by this auxiliary procedure:(define shell-sort! (lambda (v . opt) (let ((precedes? (if (null? opt) < (car opt))) (len (vector-length v))) (let ((insert! (lambda (position gap) (let ((new (vector-ref v position))) (let loop ((old-trial position) (trial (- position gap))) (if (negative? trial) ; at the left end: stop! (vector-set! v old-trial new) (let ((displaced (vector-ref v trial))) (if (precedes? new displaced) (begin (vector-set! v old-trial displaced) (loop trial (- trial gap))) (vector-set! v old-trial new))))))))) (do ((gap (gap-size-not-exceeding len) (quotient gap 3))) ((zero? gap)) (do ((position gap (+ position 1))) ((<= len position)) (insert! position gap)))))))
(define gap-size-not-exceeding (lambda (n) (let loop ((old 1) (new 4)) (if (< n new) old (loop new (+ (* 3 new) 1))))))
This document is available on the World Wide Web as
http://www.math.grin.edu/~stone/events/scheme-workshop/shellsort.html