2009-07-07 8 views
2

私はC++のプログラマーです。私は機能的に考えることができるかどうかを確認するためにこのコードを書いています:) 改善のヒント?スキームでこのmergesortを改善するには?

(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)))) 

はどこでも、私はあなたが(Pythonの風の構文で)のようなものを考えていたと思います

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

に単純化することができます:

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

ただし、機能pushようなリストの前に直接アイテムを追加しますので、次のコードのようなものだ:それは大きくはないですので、最終的に余分な追記のみ各項目のダブルコンスセルの割り当てになり

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

対処。

さらに、mergesortを魅力的にして、リストの長さを維持し、各ステップでリストの半分をソートすると、パフォーマンスが向上すると思います。しかし、これはおそらくこのような学習の例には適していません。

ような何か:

一般に
(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'はです。それがまさに私が 'mergeosrt'の始めに' length'を一度呼び出す理由です。 –

+0

OK、私はSchemeを学んでいるので、コードを正しく読まなかった。 sort-loopが呼び出されるたびにlengthが呼び出されると思いました。代わりに、一度呼び出され、変数 '' len''にバインドされていますか? '' sort-loop((l l)(len(length l))) ''で変数lに何が起こるか?新しい変数lは外側のlに束縛されていますか? – Giorgio

1

mergesortは、リスト操作の多くをやっているので、「インプレース」のサブパーツをソートすることにより、破壊的なことを行うためにはるかに優れています。 implementation of sort in PLT Scheme(SLIBに由来する共通コードなど)が表示されます。 (一見すると怖いかもしれませんが、コメントを読んでノブと最適化を無視すると、そこにすべてが表示されます)

また、SRFI-32を見ると、並べ替えの詳細な説明がありますインタフェース。

+0

あなたが投稿した最初のリンクはなくなったようです。 PLT Scheme_でソートの_implementationの新しい場所があるかどうか知っていますか? – Giorgio

+1

@Giorgio:私たちはそれ以来gitに切り替えました。これは[このファイルが今どこにあるか](http://git.racket-lang.org/plt/blob/HEAD:/collects/racket/private/ソート。rkt);私たちは 'sort 'の実装を別のものに切り替えました。参照のためのコードを参照してください。 –

+0

ありがとうございました。 – Giorgio

関連する問題