(require "sort.scm" "vector-util.scm" srfi/27) (define insert-sort! ; http://www.math.grin.edu/~stone/events/scheme-workshop/insertion.html (lambda (< v) (let ((precedes? <) (len (vector-length v))) (let ((insert! (lambda (position) (let ((new (vector-ref v position))) (let loop ((trial (- position 1))) (if (negative? trial) ; at the left end: stop! (vector-set! v 0 new) (let ((displaced (vector-ref v trial))) (if (precedes? new displaced) (begin (vector-set! v (+ trial 1) displaced) (loop (- trial 1))) (vector-set! v (+ trial 1) new))))))))) (do ((index 1 (+ index 1))) ((<= len index)) (insert! index)))))) ;;; Little test harness, 'cause I'm paraoid about tricky code. ;;; ,open i/o srfi-27 sort list-merge-sort vector-insertion-sort vector-utils ;;; For testing stable sort -- 3 & -3 compare the same. (define (my< x y) (< (abs x) (abs y))) (define (unstable-sort-test v) ; quick & heap vs simple insert (let ((v1 (vector-copy v)) (v2 (vector-copy v))) (vector-heap-sort! < v1) (insert-sort! < v2) (and (or (not (equal? v1 v2)) (not (vector-sorted? < v1))) (list v v1 v2)))) (define (stable-sort-test v) ; insert, list & vector merge sorts (let ((v1 (vector-copy v)) (v2 (vector-copy v)) (v3 (list->vector (list-merge-sort! my< (vector->list v)))) (v4 (list->vector (list-merge-sort my< (vector->list v))))) (vector-merge-sort! my< v1) (insert-sort! my< v2) (and (or (not (equal? v1 v2)) (not (equal? v1 v3)) (not (equal? v1 v4)) (not (vector-sorted? my< v1))) (list v v1 v2 v3 v4)))) (define (do-test max-size) (let lp ((i 0)) (let ((i (cond ((= i 1000) (write-char #\.) (flush-output (current-output-port)) 0) (else (+ i 1)))) (v (random-vector (random-integer max-size)))) (cond ((unstable-sort-test v) => (lambda (x) (cons 'u x))) ((stable-sort-test v) => (lambda (x) (cons 's x))) (else (lp i)))))) (define (random-vector size) (let ((v (make-vector size))) (fill-vector-randomly! v (* 10 size)) v)) (define (fill-vector-randomly! v range) (let ((half (quotient range 2))) (do ((i (- (vector-length v) 1) (- i 1))) ((< i 0)) (vector-set! v i (- (random-integer range) half)))))