Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why my merge sort implementation in Scheme is so slow?

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?

like image 263
ulidtko Avatar asked Mar 01 '11 04:03

ulidtko


1 Answers

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.

like image 145
Jeremiah Willcock Avatar answered Sep 21 '22 05:09

Jeremiah Willcock