[英]How to implement mergesort using F#
我需要使用 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)
卡住了,不知道怎么用模式匹配遍歷列表來完成拆分功能。 鑒於拆分和合並是正確的,我也不確定合並排序是否正確。
另外,在我的partern匹配情況下,列表是eigher []
或ai::af
所以我有點不確定,當我們寫ai::af
來表示一個列表時,如果列表只包含一個,a1是否等於af元素?
您還可以使用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
這就是一個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
減半為“halve”列表(l1,l2)
的元組,然后使用merge
將自我應用的結果merge
到l1
和l2
。 split
使用輔助函數aux
將任何列表轉換為由長度相差不超過 1 的相同元素組成的列表元組。
最后, merge
(上面以簡單的方式實現,但顯然不是尾遞歸的方式)將執行排序本身的一對列表重新組裝在一起。 它在內部使用將參數組合成一個元組來將參數模式匹配簡化為 3 種情況: non-empty,empty
、 empty,non-empty
和non-empty,non-empty
。
merge
尾遞歸並不太難,出於教學原因我沒有這樣做。 你可以在這個 gist 中找到尾遞歸版本。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.