2009-07-07 4 views
2

Я программист на C++, я написал этот код, чтобы увидеть, могу ли я думать функционально :) Любые подсказки для его улучшения?Как улучшить это объединение в схеме?

(define (append listOne listTwo) 
    (cond 
    ((null? listOne) listTwo) 
    (else (cons (car listOne) (append (cdr listOne) listTwo))))) 

(define (merge listOne listTwo) 
    (cond 
    ((null? listOne) listTwo) 
    ((null? listTwo) listOne) 
    ((< (car listOne) (car listTwo)) 
    (append (cons (car listOne) '()) 
      (merge (cdr listOne) listTwo))) 
    ((= (car listOne) (car listTwo)) 
    (append (cons (car listOne) '()) 
      (merge (cdr listOne) listTwo))) 
    (else (append (cons (car listTwo) '()) 
        (merge listOne (cdr listTwo)))))) 

(define (mergesort lis) 
    (cond 
    ((null? lis) '()) 
    ((null? (cdr lis)) lis) 
    (else (merge (cons (car lis) '()) 
       (mergesort (cdr lis)))))) 

(mergesort '(99 77 88 66 44 55 33 11 22 0)) 
+0

Это выглядит довольно стандартно для меня :) Вот еще одна версия: https://ironscheme.svn.codeplex.com/svn/IronScheme/IronScheme.Console/build/sorting.ss – leppie

+0

О, спасибо, я возьму посмотрите на IronScheme :) – AraK

+0

Я взял на себя смелость форматировать свой код. – Svante

ответ

3

Там только один небольшое улучшение, что я вижу:

(append (cons (car listTwo) '()) 
       (merge listOne (cdr listTwo)))) 

может везде быть упрощена

(cons (car listTwo) 
     (merge listOne (cdr listTwo))) 

Я думаю, что вы думали о чем-то вроде (в Python-Эск синтаксис) :

[car(listTwo)] + merge(listOne, cdr(listTwo)) 

Но недостатки добавляет элемент непосредственно в передней части списка, как функциональный push, так как следующий код:

push(car(listTwo), merge(listOne, cdr(listTwo))) 

В конечном счете дополнительные Append только результаты в двойном распределении против ячейки для каждого элемента, так что это не большая по рукам.

Кроме того, я думаю, что вы можете получить более высокую производительность, если вы сделали mergesort fancier так, чтобы он поддерживал длину списка и сортировал обе половины списка на каждом шаге. Это, вероятно, не подходит для учебного примера, подобного этому.

Что-то вроде:

(define (mergesort l) 
    (let sort-loop ((l l) (len (length l))) 
    (cond 
     ((null? l) '()) 
     ((null? (cdr l)) l) 
     (else (merge (sort-loop (take (/ len 2) l) (/ len 2))) 
        (sort-loop (drop (/ len 2) l) (/ len 2))))))))) 
(define (take n l) 
    (if (= n 0) 
     '() 
     (cons (car l) (take (sub1 n) (cdr l))))) 
(define (drop n l) 
    (if (= n 0) 
     l 
     (drop (sub1 n) (cdr l)))) 
+0

Не нужно ли функции длины перемещаться по всему списку? Это может быть довольно дорогостоящим, поскольку это необходимо для каждого рекурсивного вызова mergesort. Я бы определил функцию split без использования длины. Он становится немного более сложным, но он должен быть более эффективным. Однако не проверял. – Giorgio

+0

'mergesort' не рекурсивный. 'sort-loop' есть. Именно поэтому я называю 'length' один раз в начале' mergeosrt'. –

+0

ОК, я изучаю схему, поэтому я не читал код правильно. Я думал, что длина вызывается каждый раз, когда вызывается цикл сортировки. Вместо этого он называется один раз и привязан к переменной '' len''? Что происходит с переменной l в '' sort-loop ((l l) (len (length l))) ''? Является ли новая переменная l связанной с внешней l? – Giorgio

1

В общем, mergesort делает много список манипуляций, поэтому гораздо лучше делать вещи деструктивно сортировкой югу частей «на месте». Вы можете увидеть implementation of sort in PLT Scheme, например, общий код, созданный в SLIB. (Это может показаться пугающим с первого взгляда, но если вы прочтете комментарии и проигнорируете ручки и оптимизацию, вы увидите все это там.)

Кроме того, вы должны посмотреть на SRFI-32 для расширенного обсуждения сортировки интерфейс.

+0

Первая ссылка, которую вы опубликовали, похоже, ушла. Вы знаете, есть ли новое место для _implementation sort в PLT Scheme_? – Giorgio

+1

@Giorgio: С тех пор мы переключились на git, где [здесь вы можете найти этот файл сейчас] (http://git.racket-lang.org/plt/blob/HEAD:/collects/racket/private/ Сортировать.РКТ); но мы также переключили реализацию 'sort' на что-то другое. См. Код для ссылок. –

+0

Большое спасибо за информацию. – Giorgio