I'm aware of Racket's stdlib, but I want to implement a sorting function by myself as an excercise. I decided to use merge sort algorithm as it is naturally defined in recursive terms. Pretty soon I've come up with working code, but it works too slow. It seems to me that the running time is exponential of the list size, though theoretically it should be O(n·log n)
.
Here is my code:
#lang racket(define (pair x y) (list x y))
(define (split input) (cond [(empty? input) (pair null null)] [(empty? (rest input)) (pair input null)] [else (let [(tail (cddr input))] (pair (cons (first input) (first (split tail))) (cons (second input) (second (split tail)))))]))
(define (merge input1 input2) (if (ormap empty? (list input1 input2)) (append input1 input2) (if (< (first input1) (first input2)) (cons (first input1) (merge (rest input1) input2)) (cons (first input2) (merge input1 (rest input2))))))
(define (sort input) (cond [(empty? input) null] [(empty? (rest input)) input] [else (let [(halves (split input))] (merge (sort (first halves)) (sort (second halves))))]))
(define (sorted? input) (cond [(empty? input) #t] [(empty? (rest input)) #t] [else (and (<= (first input) (second input)) (sorted? (rest input)))]))
It seems that I use some "atomic" operation which doesn't run in constant time as I might think, however I can't figure out which. Sorting of 30 random items is instantaneous, 40 items are processed in a couple of seconds, 50 items take half a minute. So I wonder, where is the snag?
In split
, you are calling (split tail)
twice rather than using let
to run it once and store the result into a variable. That is probably making split
take exponential time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With