2016-11-22 2 views
1

Без использования выражений case (которые входят в следующий раздел класса), я не понимаю, почему следующее не выполняет quicksort. Он попадает в петлю где-то и никогда не заканчивается.quicksort in 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 с)), но я, хотя прежний был лучше стиль, поскольку она требует только одного рекурсию с каждым раундом. Я думаю, я должен сказать, что «splitAt» делит список на большее или равное второму аргументу и меньше, и создает кортеж). Добавить объединяет 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 всегда будет уменьшать размер?

В идеале вы должны поставить splitAt и append, так как они не являются библиотечными функциями. Вы можете рассмотреть возможность использования встроенного добавления под названием @ и встроенного List.partition для формирования splitAt.

Сравнить против этого найденного где-то на межсетях:

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'ing всего списка снова, несомненно, не уменьшит размер. По сравнению с версией, приведенной в моем ответе, удаление 'x' из списка ввода каждый раз гарантирует, что последующие вызовы' quicksort' имеют меньше элементов, чем раньше. –

0

Поскольку это не домашнее задание ...

Обратите внимание, что если xs = [1,2] затем splitAt(xs hd xs) возвращается ([1,2],[]) поэтому попытка разобраться [1,2] этим версия qsort сводится к ... сортировке [1,2] снова. Это никогда не закончится.

Вместо этого я буду защищать splitAt от хвост xs. Минимальная твик в код, чтобы оставить append и splitAt в одиночку, но переписать 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 один раз к добавленному split будет пытаться уменьшить qsort до применения qsort к списку, который имеет тот же размер, что и исходный список.

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

+0

Действительно, это работает, и я благодарю вас. Я вижу, что вам нужно применить qsort дважды, и простое изменение использования tl xs в splitAt также сильно изменилось. SML действительно забавный, интересный и образовательный. –

+0

@NealKoss: «простое изменение использования' tl xs' в 'splitAt' также сильно изменилось»: Нет, это + использование '(hd xs) :: ...' в полученном результате * * разнице , Благодаря этому устройству Джон убеждается, что, когда 'qsort' вызывает себя дважды, каждый из этих вызовов происходит с меньшим количеством аргументов, чем раньше. Таким образом, он обеспечивает верхнюю границу того, сколько рекурсивных вызовов может выполнять функция. Вы можете видеть, сколько это? И да, SML действительно весело! :) (Пока раздражающие люди в Интернете не заставляют вас заниматься математикой!) –