ML中的快速排序

时间:2016-11-22 23:48:56

标签: quicksort sml smlnj ml

不使用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:这只是一个练习题,不是考试或家庭作业。

2 个答案:

答案 0 :(得分:1)

  

它进入某个循环而永远不会结束。

您的问题最有可能在列表上调用qsort,该列表在递归调用时不会减小大小。也许和append(qsort (#2 s), qsort (#1 s))一起去。但即便如此,你能确定#1 s#2 s中的每一个都会缩小吗?

理想情况下,您应该提供splitAtappend,因为它们不是库函数。您可以考虑使用名为@的内置附加内容和内置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的尾部。对代码进行最小调整就是单独留下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真的很有趣。你应该享受下一章。