不使用case表达式(在类的下一部分中),我不明白为什么以下不执行快速排序。它进入某个循环并永远不会结束。
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
我使用append(qsort(#2 s),qsort(#1 s))得到同样的问题,但我虽然前者是更好的样式,因为它只需要每轮一次递归。 我想我应该说'splitAt'将列表分成大于或等于第二个参数,并且小于,并创建一个元组)。附加连接2个列表。
PS:这只是一个练习题,不是考试或家庭作业。
答案 0 :(得分: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
答案 1 :(得分:0)
因为这不是作业......
请注意,如果xs = [1,2]
,则splitAt(xs hd xs)
会返回([1,2],[])
,因此,此[1,2]
版本对qsort
进行排序的尝试将减少为... [1,2]
1}}再次。那将永远不会终止。
相反,我建议将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
一次应用于附加的拆分会尝试将qsort
缩减为将qsort
应用于与原始列表大小相同的列表。
当你进行模式匹配时,SML真的很有趣。你应该享受下一章。