下面的代码是f#中mergesort的代码,我必须重写它,所以它使用模式匹配。
let rec msort xs =
let sz = List.length xs
if sz < 2 then xs
else let n = sz / 2
let ys = xs.[0..n-1]
let zs = xs.[n..sz-1]
in merge (msort ys) (msort zs)
到目前为止,我已经到了这里:
let rec msort (vs: int list) =
let sz = List.length xs
match xs with
| List.length < 2 -> vs
| _ ->
let n = sz / 2
let ys = xs.[0..n-1]
let zs = xs.[n..sz-1]
in merge (msort ys) (msort zs)
我似乎无法找到更好的方法。有没有人可以帮助我?
答案 0 :(得分:2)
我可能会这样做:
let rec msort (values: int list) =
let n = values.Length / 2
if n = 0
then values
else let rec merge (xs: int list) (ys: int list) =
match (xs, ys) with
| ([], ys) -> ys
| (xs, []) -> xs
| (x :: xs1, y :: ys1) ->
if x < y
then x :: merge xs1 ys
else y :: merge xs ys1
let (first, second) = values |> List.splitAt n
merge (msort first) (msort second)
模式匹配对于初始逻辑(列表的长度,长度为0和1的早期出口)并不太有用,但我认为在匹配子列表后的情况时,它更具可读性。分裂。即使如此,msort
部分中只有一个if / then,如果您真的想要它可以替换为模式匹配:
let rec msort (values: int list) =
match values.Length / 2 with
| 0 -> values
| n ->
let rec merge (xs: int list) (ys: int list) =
match (xs, ys) with
| ([], ys) -> ys
| (xs, []) -> xs
| (x :: xs1, y :: ys1) ->
if x < y
then x :: merge xs1 ys
else y :: merge xs ys1
let (first, second) = values |> List.splitAt n
merge (msort first) (msort second)
这只会在if/then
实施中仅留下x<y
merge
,我不会改变它。
答案 1 :(得分:1)
几乎相同,但我建议自定义拆分:
let split2 (li: int list) =
let n = (List.length li) / 2
let rec looprec (len: int) (l1: int list) (l2: int list) =
if len > 0 then
match l1 with
| x::tail -> looprec (len-1) tail (x::l2)
| _ -> (List.rev l2, l1)
else
(List.rev l2, l1)
in looprec n li []
let rec merge (l1: int list) (l2: int list) =
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 msort (li: int list) =
match li with
| [] -> []
| [x] -> [x]
| _ -> let (l1,l2) = split2 li
in merge (msort l1) (msort l2)
let d= msort [3;20;12]
printfn "%A" d