有人可以帮助解释这种合并排序算法是如何工作的吗?
Posted
技术标签:
【中文标题】有人可以帮助解释这种合并排序算法是如何工作的吗?【英文标题】:Can someone please help explain how this merge sort algorithm works? 【发布时间】:2021-10-23 22:46:39 【问题描述】:我昨天开始学习 F#,但在所有新的函数式编程方面都有些吃力。
我试图理解这种使用拆分功能的合并排序实现。拆分函数定义为:
let rec split = function
| [] -> ([], [])
| [a] -> ([a], [])
| a :: b :: cs -> let (r, s) = split cs
in (a :: r, b :: s)
按照我的理解,我们获取一个列表并返回一个列表元组,将列表分成两半。如果我们在空列表上进行模式匹配,我们会返回一个空列表元组,如果我们在一个包含一个元素的列表上匹配,我们会返回一个包含该列表和一个空列表的元组,但是递归的情况让我无法理解。
a :: b :: cs 表示 a 前置 b 前置到 cs,对吗?那么这是列表至少有3个元素的情况吗?如果是这样,我们返回两个值,r 和 s,但是我之前没有看到使用过这个“in”关键字。据我所知,我们将第一个元素 a 放在 r 前,将第二个元素 b 放在 s 前,然后在列表的其余部分 cs 上拆分。但这似乎并没有将列表分成两半。
谁能帮助解释递归案例的工作原理?非常感谢。
【问题讨论】:
【参考方案1】:当列表中只有两个项目时,cs 为 []。当列表中有 3 个或更多项目时,它会递归,其中 cs 是没有前两个项目的列表。当只有一项时它返回 [a],[] 并且当列表为空时它返回 [],[] 。
【讨论】:
【参考方案2】:在这种情况下,您可以忽略 in
关键字,因此您可以将最后一种情况理解为:
| a :: b :: cs ->
let (r, s) = split cs
(a :: r, b :: s)
请注意,这将匹配任何长度为 2 或更大的列表,而不是您最初认为的 3。当列表正好有两个元素时,cs
将是空列表。
所以在这种情况下发生了什么:
如果列表至少有 2 个元素: 将第一个元素命名为a
将第二个元素命名为b
将列表的其余部分命名为 cs
(即使它是空的)
递归拆分cs
,这给了我们两个新列表,r
和s
再创建两个新列表:
在r
前面带有a
的一个
另一个在s
前面带有b
返回两个新列表
你can see this in operation如果你这样调用函数:
split [] |> printfn "%A" // [],[]
split [1] |> printfn "%A" // [1],[]
split [1; 2] |> printfn "%A" // [1],[2]
split [1; 2; 3] |> printfn "%A" // [1; 3],[2]
split [1; 2; 3; 4] |> printfn "%A" // [1; 3],[2; 4]
split [1; 2; 3; 4; 5] |> printfn "%A" // [1; 3; 5],[2; 4]
更新:in
究竟做了什么?
in
关键字只是将let
绑定放在表达式中的一种方式。因此,例如,我们可以编写let x = 5 in x + x
,这是一个值为10
的表达式。此语法继承自 OCaml,当您想将整个表达式写在一行上时仍然很有用。
在现代 F# 中,我们可以改用空格/缩进,将 in
关键字替换为换行符。所以现在,我们通常会这样写这个表达式:
let x = 5
x + x
这两种形式在语义上是等价的。更多详情here.
【讨论】:
非常感谢,这很有帮助。我太专注于我见过的第一个合并排序实现,它只是将列表从中间拆分,因为这个递归地向下推进列表,将所有其他元素附加到 r 或 s。 另外,“in”的目的是什么?您提到在这种情况下没有必要,是不再使用的旧语法吗? 是的,它是一种很少使用的旧(“重”)语法。我用更详细的解释更新了我的答案。以上是关于有人可以帮助解释这种合并排序算法是如何工作的吗?的主要内容,如果未能解决你的问题,请参考以下文章
这是 WordPress 中的 .htaccess 代码。有人可以解释它是如何工作的吗?
有人能解释一下staticmethod的源代码在python中是如何工作的吗