递归函数中大整数的异常 Stack_overflow

Exception Stack_overflow for big integer in recursive functions

我的快速排序代码适用于 N(列表大小)的某些值,但对于大值(例如,N = 82031),OCaml 返回的错误是:

Fatal error: exception Stack_overflow.

我做错了什么?
由于 OCaml 不支持大值的递归函数,我是否应该创建一个迭代版本?

let rec append l1 l2 =
  match l1 with
    | [] -> l2
    | x::xs -> x::(append xs l2)


let rec partition p l =
  match l with
    | [] -> ([],[])
    | x::xs ->
      let (cs,bs) = partition p xs in
      if p < x then
        (cs,x::bs)
      else
        (x::cs,bs)


let rec quicksort l = 
  match l with
  | [] -> []
  | x::xs ->
      let (ys, zs) = partition x xs in
      append (quicksort ys) (x :: (quicksort zs));;

问题是 none 你的递归函数是尾递归的。

尾递归意味着调用者不应执行进一步的操作(参见 here)。在那种情况下,不需要保留调用函数的环境,堆栈也不会充满递归调用的环境。像 OCaml 这样的语言可以以最佳方式编译它,但为此你需要提供尾递归函数。

比如你的第一个函数,append :

let rec append l1 l2 =
  match l1 with
    | [] -> l2
    | x::xs -> x::(append xs l2)

如你所见,在 append xs l2 被调用后,调用者需要执行 x :: ... 并且这个函数以非尾递归结束。

另一种尾递归方式是这样的:

let append l1 l2 =
  let rec aux l1 l2 =
    match l1 with
      | [] -> l2
      | x::xs -> append xs (x :: l2)
  in aux (List.rev l1) l2

但是,实际上,您可以尝试使用 List.rev_append 知道此函数将追加 l1l2l1 将被反转(List.rev_append [1;2;3] [4;5;6] 给出 [3;2;1;4;5;6])

尝试将您的其他函数转换为尾递归函数,看看它能给您带来什么。

最好解决上面提到的根本问题,但如果你真的需要大筹码,设置ulimit -s。另见: