如何使用F#

时间:2018-12-29 13:53:09

标签: .net algorithm sorting f# mergesort

我需要使用F#实现合并排序,为此,我需要2个辅助功能:拆分和合并,其中“拆分”将一个列表拆分为两个大小相差最大为1的较小列表。创建分割功能。这是到目前为止我实现的合并和拆分功能:

let rec merge (l: 'a list, m: 'a list)=
    match l,m with
    |[],[] -> []
    |[],mi::mf -> mi::mf
    |li::lf,[] -> li::lf
    |li::lf, mi::mf -> if li<mi then li::merge (lf,mi::mf)
                       else mi::merge(li::lf,mf)


   let split (l: 'a list)=
        let n= l.Length
        if n%2=1 then
            for i in  1..n/2 do

let rec mergesort (l :'a list)=
    let (left,right)=split l
    if left.Length>1 || right.Length>1 then 
        merge(mergesort left,mergesort right)
    else
        merge(left,right)

我被困住了,我不知道如何使用模式匹配来遍历列表以完成拆分功能。考虑到拆分和合并正确,我也不确定mergesort是否正确。

此外,在我的部分匹配案例中,列表是[]ai::af的邻居,所以我有点不确定,当我们写ai::af来表示列表时,a1等于到列表是否仅包含一个元素的话?

2 个答案:

答案 0 :(得分:1)

您也可以使用List.splitInto来实现自己的拆分功能。

let rec mergeSort lst =
    let rec merge = function 
        | l, [] -> l
        | [], l -> l
        | x::xs, y::ys -> if x < y 
                          then x :: merge (xs, y::ys)
                          else y :: merge (x::xs, ys)
    match List.splitInto 2 lst with
    | [l1;l2] ->  merge (mergeSort l1, mergeSort l2)
    | l -> List.concat l

答案 1 :(得分:0)

这是一个简单的mergesort实现的样子:

let split list =
    let rec aux l acc1 acc2 =
        match l with
            | [] -> (acc1,acc2)
            | [x] -> (x::acc1,acc2)
            | x::y::tail ->
                aux tail (x::acc1) (y::acc2)
    in aux list [] []

let rec merge l1 l2 = // this version is NOT tail-recursive
    match (l1,l2) with
        | (x,[]) -> x
        | ([],y) -> y
        | (x::tx,y::ty) ->
            if x <= y then x::merge tx l2
            else y::merge l1 ty

let rec mergesort list = 
    match list with
        | [] -> []
        | [x] -> [x]
        | _ -> let (l1,l2) = split list
               in merge (mergesort l1) (mergesort l2)

精心设计的精确模式匹配是它的核心。

主要部分mergesort递归应用长度大于1的列表的拆分,然后合并通过自我应用排序的拆分后的两半:

  • 对于空参数或单例,它只是将其作为结果回显
  • 否则(模式匹配的最后一种情况),它使用split将参数list减半成一个“一半”列表(l1,l2)的元组,然后使用merge来减半将自我应用的结果合并到l1l2

split使用辅助函数aux,该函数将任何列表转换为由相同元素组成的列表元组,这些元素的长度相差不超过1。

最后,merge(上面以简单的方式实现,但显然不是尾部递归的方式)将列表对重新组合在一起,从而进行排序。它使用内部将参数组合到元组中来简化仅3种情况的参数模式匹配:non-empty,emptyempty,non-emptynon-empty,non-empty

使merge尾递归并不是很困难,出于教学上的原因,我没有这么做。您可能会在this gist中找到尾递归版本。