2016-11-22 12 views
1

ケースの表現(クラスの次のセクションにあります)を使用せずに、私はクイックソートをやっていない理由を理解できません。それはどこかのループに入り、決して終わらない。MLのクイックソート

splitAtとappendは既に厳しくテストされていますが、ここではそれらのコードがあります。

fun append(xs, ys) = 
if null xs 
then ys 
else (hd xs) :: append(tl xs, ys) 

fun splitAt(xs : int list, x : int) = 
let 
    fun sp(ys : int list, more : int list, less : int list) = 
     if null ys 
     then (more, less) 
     else 
      if hd ys < x 
      then sp(tl ys, more, append(less, [hd ys])) 
      else sp(tl ys, append(more, [hd ys]), less) 
in 
    sp(xs, [], []) 
end 

fun qsort(xs : int list) = 
    if length xs <= 1 
    then xs 
    else 
    let 
     val s = splitAt(xs, hd xs) 
    in 
     qsort(append(#2 s, #1 s)) 
    end 

そして、私は(のqsort(#2秒)、のqsort(#1 S))追加使用して同じ問題を取得しますが、私前者はそれだけで各ラウンドを持つ単一の再帰を必要とするため、より良いスタイルでしたが。 私は 'splitAt'はリストを2番目の引数よりも大きく、2番目の引数よりも小さく、そしてより小さい、そしてタプルを作成すると言うべきだと思います。 Appendは2つのリストを連結します。

PS:これは練習問題であり、テストや宿題ではありません。

+0

'splitAt'と' append'のコードを提供する必要があります。コードがバグの場合、バグが存在する可能性があります。それを言いました - 'append(qsort(#2 s)、qsort(#1 s))のようなものではないでしょうか? ' –

答えて

1

ループのどこかに入り、決して終了しません。

再帰呼び出し時にサイズが縮小されないリストでqsortが呼び出される可能性があります。おそらくappend(qsort (#2 s), qsort (#1 s))に行ってください。しかし、それでも、#1 s#2 sのそれぞれが常にサイズが小さくなることを確認できますか?

splitAtappendはライブラリ機能ではないため、入力する必要があります。 @という組み込みの付属物と組み込みのList.partitionを使用してsplitAtを形成することを検討することもできます。

はinterwebs上のどこかに見つかったこの1に対する比較:

fun quicksort [] = [] 
    | quicksort (x::xs) = 
    let 
     val (left, right) = List.partition (fn y => y < x) xs 
    in 
     quicksort left @ [x] @ quicksort right 
    end 
+0

パターンマッチを使用したくないのは、次の章にあります。これらの問題は現在のツールで解決されるはずです。しかし、あなたが書いたものを変換すると、私のqsortと同じで、最後のステートメントはappend(qsort(#2 s)、qsort(#1 s))となり、再び無限ループになります。 –

+0

私が言ったように、おそらくこれは、 'qsort'のように、リスト全体のサイズが決して縮小されないためです。私の答えで与えられたバージョンと比較すると、毎回入力リストから 'x'を取り除くことで、後で' quicksort'を呼び出す際に、以前よりも要素数が少なくなっています。 –

0

これは宿題ではないので...

注意このことにより、[1,2]をソートするのでxs = [1,2]その後、splitAt(xs hd xs)戻り([1,2],[])かの試みということqsortのバージョンは... [1,2]を再度ソートします。それは決して終わらないでしょう。

代わりに、splitAtをxsのテールに適用することを提唱します。あなたのコードに最小限の微調整だけではappendsplitAtを残すことなく、としてqsortの書き換えをされています

fun qsort(xs : int list) = 
    if length xs <= 1 
    then xs 
    else 
    let 
     val s = splitAt(tl xs, hd xs) 
    in 
     append(qsort(#2 s), (hd xs) :: qsort(#1 s)) 
    end; 

そして、例えば、

- qsort [4,2,1,2,3,6,4,7]; 
val it = [1,2,2,3,4,4,6,7] : int list 

あなたが結果を追加し、その後二回qsortを適用することが重要です。追加の分割にqsortを一度適用しようとするとqsortを元のリストと同じサイズのリストにqsortを適用するまで減らそうとしています。

パターンマッチングが始まると、SMLは本当に楽しくなります。あなたは次の章を楽しむべきです。

+0

それは確かに動作し、私はあなたに感謝します。私はあなたがqsortを2回適用しなければならないことを知っており、splitAtのtl xsを使用する単純な変更も大きな違いをもたらしました。 SMLは確かに楽しく、面白く、教育的です。 –

+0

@NealKoss: 'splitAt'の' tl xs'を使った単純な変更は大きな違いをもたらしました ":いいえ、+その結果に'(hd xs):: ... ' 。このデバイスによって、Johnは 'qsort'がそれ自身を2回呼び出すときに、それらの呼び出しのそれぞれが前よりも少ない数の引数で起こることを確認します。こうすることで、関数が何回再帰呼び出しを行うことができるかが保証されます。それはどれくらいあるのでしょうか?そしてはい、SMLは本当に楽しいです! :)(インターネット上の迷惑な人々があなたに数学をさせていない限り!) –