2009-07-07 7 views
2

Je suis un programmeur C++, j'ai écrit ce code pour voir si je peux penser fonctionnellement :) Des conseils pour l'améliorer?Comment améliorer ce mergesort dans le schéma?

(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

Il me semble assez standard :) Voici une autre version: https://ironscheme.svn.codeplex.com/svn/IronScheme/IronScheme.Console/build/sorting.ss – leppie

+0

Oh merci, je vais prendre un Regardez IronScheme :) – AraK

+0

J'ai pris la liberté de formater votre code. – Svante

Répondre

3

Il n'y a qu'une petite amélioration que je vois:

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

peut partout être simplifié à

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

Je pense que vous pensiez à quelque chose comme (dans la syntaxe Python-esque) :

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

Mais contre ajoute un élément directement à l'avant d'une liste, comme un push, il est donc comme le code suivant fonctionnel:

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

En fin de compte l'append supplémentaire résulte que dans l'allocation de double cellule de contre pour chaque élément, il est donc pas un grand traiter.

En outre, je pense que vous pourriez obtenir de meilleures performances si vous avez fait mergesort colombophile de sorte qu'il conserve la longueur de la liste et trie les deux moitiés de la liste à chaque étape. Ce n'est probablement pas approprié pour un exemple d'apprentissage comme celui-ci, cependant.

Quelque chose comme:

(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

La fonction de longueur ne doit-elle pas traverser toute la liste? Cela peut être assez coûteux car cela doit être fait pour chaque appel récursif à mergesort. Je définirais la fonction split sans utiliser de longueur. Ça devient un peu plus complexe mais ça devrait être plus efficace. Je ne l'ai pas testé cependant. – Giorgio

+0

'mergesort' n'est pas récursif. 'sort-loop' est. C'est exactement pourquoi j'appelle 'length' une fois au début de' mergeosrt'. –

+0

OK, j'apprends Scheme donc je n'ai pas lu le code correctement. Je pensais que la longueur est appelée chaque fois que sort-loop est appelée. Au lieu de cela, est-il appelé une fois et lié à la variable «len»? Qu'arrive-t-il à la variable l dans '' sort-loop ((l l) (len (longueur l))) ''? Une nouvelle variable l est-elle liée à la l externe? – Giorgio

1

En général, mergesort fait beaucoup de manipulations de la liste, il est donc préférable de faire les choses par le tri des pièces destructivement sous « en place ». Vous pouvez voir le implementation of sort in PLT Scheme par exemple d'un code commun, qui provient de SLIB. (Cela peut sembler intimidant à première vue, mais si vous lisez les commentaires et ignorez les boutons et les optimisations, vous verrez tout.)

De plus, vous devriez regarder SRFI-32 pour une discussion étendue d'un tri interface.

+0

Le premier lien que vous avez posté semble avoir disparu. Savez-vous s'il y a un nouvel emplacement pour _implementation de tri dans PLT Scheme_? – Giorgio

+1

@Giorgio: Depuis, nous sommes passés à git, qui est [où vous pouvez trouver ce fichier maintenant] (http://git.racket-lang.org/plt/blob/HEAD:/collects/racket/private/ Trier.rkt); mais nous avons aussi changé l'implémentation de 'sort' en quelque chose de différent. Voir le code pour les références. –

+0

Merci beaucoup pour l'information. – Giorgio

Questions connexes