F#中的Quicksort - 语法问题

时间:2009-12-30 19:10:48

标签: f# quicksort

我有一个简单的f#快速排序功能,定义为:

let rec qsort(xs:List<int>) =

let smaller = xs |> List.filter(fun e -> e < xs.Head)
let larger = xs |> List.filter(fun e -> e > xs.Head)
match xs with
| [] -> []
| _ -> qsort(smaller)@[xs.Head]@qsort(larger)

f#中有没有办法像Haskell一样写它:

qsort       :: [Int] -> [Int]
qsort []     = []
qsort (x:xs) =
qsort smaller ++ [x] ++ qsort larger
where
  smaller = [a | a <- xs, a <= x]
  larger  = [b | b <- xs, b >= x]

我知道f#算法缺少&lt; =和&gt; =。问题更多的是语法/可读性。

感谢。

8 个答案:

答案 0 :(得分:13)

这是我能想到的最“Haskellian”方式,唯一缺少的是能够将较小/较大的声明声明为“where”子句:

let rec qsort:int list -> int list = function
    | [] -> []
    | x::xs -> let smaller = [for a in xs do if a<=x then yield a]
               let larger =  [for b in xs do if b>x then yield b]
               qsort smaller @ [x] @ qsort larger

我知道这不是你问题的一部分,但是我会使用List.partition在一次传递中将列表拆分为更小/更大:

let rec qsort = function
    | [] -> []
    | x::xs -> let smaller,larger = List.partition (fun y -> y<=x) xs
               qsort smaller @ [x] @ qsort larger

答案 1 :(得分:9)

您希望第二个匹配子句为x :: xs,并使用Haskell示例使用++的@(append)运算符:

let rec qsort xs =
  match xs with
  | [] -> []
  | x :: xs ->
      let smaller = qsort (xs |> List.filter(fun e -> e <= x))
      let larger  = qsort (xs |> List.filter(fun e -> e >  x))
      smaller @ [x] @ larger

它与案例语法中的Haskell定义不完全相同,但希望对你来说足够相似!

答案 2 :(得分:5)

这似乎尽可能简洁(结合其他答案的想法,并为运营商使用currying):

let rec qsort = function
| [] -> []
| (x:int) :: xs ->
    let smaller = List.filter ((>=) x) xs
    let larger  = List.filter ((<) x) xs
    qsort smaller @ [x] @ qsort larger

答案 3 :(得分:4)

...或者您可以使用CPS创建尾递归qsort:

let qSort lst = 
   let rec qs l cont = 
       match l with
       | []      -> cont []
       | (x::xs) -> qs (List.filter (fun e -> e <= x) xs) (fun smaller ->
                    qs (List.filter (fun e -> e >  x) xs) (fun larger  ->
                        smaller @ (x :: larger) |> cont))
   qs lst id

答案 4 :(得分:2)

haskell'where'语法,它允许你在定义之前使用函数的名称,类型映射到f#'让rec ...和'

let qsort xs =
    let rec sort xs = 
        match ls with
        |[] -> ....
        |h::t -> (smaller t) @ h @ (larger t)

    and smaller ls =    //the 'and' lets you define the 
                        //  function after where it is used, 
                        //  like with 'where' in haskell
         ... define smaller in terms of sort
    and larger ls =
         ... same

    sort xs

答案 5 :(得分:1)

let  rec QuickSort l =
        match   l with  
        |  []  ->  []
        |   _   ->  QuickSort([for e in l do if e < (List.head l) then yield e]) @[(List.head l)]@ QuickSort([for e in l do if e > (List.head l) then yield e])

答案 6 :(得分:1)

不要忘记List有分区方法,所以

let rec quicksort ls =
    match ls with
    | [] -> []
    | h :: t -> let fore, aft = List.partition (fun i -> i < h) t
                (quicksort fore) @ (h :: quicksort aft)

答案 7 :(得分:0)

几年前我在F#中以非常紧迫的方式对排序算法进行了一些分析;我试图击败.NET股票实施,并设法这样做here。我今天要回复自己,但是FPish不会让我创建一个帐户。哎呀!要在某处做我的帖子,这里和其他地方一样好,大声笑......

在昨天阅读“了解大好的Haskell”时,作者为实现快速排序设置了一个示例。描述非常清楚,甚至在我得到示例代码之前,一个优雅的递归解决方案(在Haskell中)突然出现在我脑海中。猜猜我从来没有真正直接感受到quicksort如何做到这一点,因为这个简单的解决方案非常简单,如果效率不高的话。

这是我在F#中的版本:

let rec quicksort = function
    | [] -> []
    | pivot :: xs ->
        (left pivot xs) @ pivot :: (right pivot xs)
and left pivot xs = quicksort [ for x in xs do if x <= pivot then yield x ]
and right pivot xs = quicksort [ for x in xs do if x > pivot then yield x ]

而且,等效的Haskell(我喜欢这个......干净!):

quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (pivot : xs) =
    left ++ pivot : right
    where
        left = quicksort [ x | x <- xs, x <= pivot ]
        right = quicksort [ x | x <- xs, x > pivot ]

对于笑脸,这里是另一个F#版本(主要是尾递归),大约是普通版本速度的2倍。尽管如此,我还是不打算把它放在原来的帖子上,所以不知道几年前我在FPish.net(FSHub)的OP中如何叠加到可变版本......

let rec quicksort' xs =
    let rec aux pivot left right = function
        | [] -> (quicksort' left) @ pivot :: (quicksort' right)
        | x :: xs ->
            if x <= pivot then
                aux pivot (x :: left) right xs
            else
                aux pivot left (x::right) xs
    match xs with
    | [] -> []
    | x :: xs -> aux x [] [] xs