2016-11-22 295 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 

我也得到使用追加(快速排序(#2秒),快速排序(#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的尺寸总是会减小吗?

理想情况下,您应该提供splitAtappend,因为它们不是库函数。您可以考虑使用名为@的内置追加程序和内置的List.partition来形成splitAt

比较反对这一个地方发现了interwebs:

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'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''与我的答案给出的版本相比, –

0

因为这不是功课...

注意,如果xs = [1,2]然后splitAt(xs hd xs)回报([1,2],[])所以试图通过这种[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两次,然后追加结果。 Tryng将qsort应用一次到附加分割将试图减少qsort到应用qsort到与原始列表大小相同的列表。

当你进行模式匹配时,SML真的变得很有趣。你应该享受下一章。

+0

确实有效,我感谢你。我看到你必须使用qsort两次,而在splitAt中使用tl xs的简单改变也有很大的不同。 SML确实很有趣,有趣且富有教育意义。 –

+0

@NealKoss:“在splitAt中使用'tl xs'的简单改变也产生了很大的不同”:不,在结果中使用'(hd xs):: ...'的+使得*差异。通过这个设备,约翰确保当'qsort'自己调用两次时,每个调用都会以比以前少的参数发生。这样他确保函数可以进行多少次递归调用的上限。你能看到这是多少?是的,SML确实很有趣! :)(只要互联网上的烦人的人不会让你做数学!) –