在OCaml中基于列表的快速排序中的stack_overflow

时间:2013-03-04 17:44:12

标签: functional-programming ocaml

以下是list-based quicksort的实现:

let partition pivot l = 
    let rec p left right = function
      | [] -> (left, right)
      | hd::tl ->
    let c = compare pivot hd
    in 
    if c > 0 then
      p (hd::left) right tl
    else 
      p left (hd::right) tl
    in
    p [] [] l;;

let quicksort l =
  let rec qs = function
    | [] -> []
    | pivot::tl ->
      let (left, right) = partition pivot tl
      in 
      (qs left) @ (pivot::(qs right))
  in 
  qs l;;

当我使用100,000列表进行尝试时,它很好并且没有问题。

但是,如果我使用1,000,000进行尝试,则会出现stack_overflow错误。


我不明白为什么它会给stack_overflow,因为我认为堆栈大小应该像log1000000 ~ 20一样,对吧?

3 个答案:

答案 0 :(得分:5)

我会假设@运算符将使用线性数量的堆栈。 (这只是在列表上进行快速排序的问题之一。)

以下是Pervasives模块中@的定义:

let rec ( @ ) l1 l2 =
  match l1 with
    [] -> l2
  | hd :: tl -> hd :: (tl @ l2)

这是一个非常缓慢的排序。如果你真的想要这个,你必须要聪明得多。至少你需要一个尾递归版@

答案 1 :(得分:1)

Quicksort不能用于链接列表。它不起作用。在列表上使用的正确排序算法是合并排序。 基本上,只要在算法中使用列表连接,就应该意识到你做得不对,或者你应该使用其他数据结构。列表有许多优点,连接不是其中之一。

答案 2 :(得分:0)

如前所述,问题在于@。这不是一个无法解决的问题:您需要将内部排序函数重新定义为一个排序和连接的函数。

 let partition pivot l = 
     let rec p left right = function
       | [] -> (left, right)
       | hd::tl ->
     let c = compare pivot hd
     in 
     if c > 0 then
       p (hd::left) right tl
     else 
       p left (hd::right) tl
     in
     p [] [] l;;

 let quicksort l =
   let rec qs l acc = 
   match l with
     | [] -> acc
     | pivot::tl ->
       let (left, right) = partition pivot tl
       in 
       qs left (pivot::(qs right acc)) 
   in 
   qs l [];;