有人可以帮助解释这种合并排序算法是如何工作的吗?

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,这给了我们两个新列表,rs 再创建两个新列表: 在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中是如何工作的吗

为啥逻辑适用于函数但不使用类,合并排序算法

有人可以解释这些 apache bench 结果吗,有啥突出的吗?

调试和二分查找

快速排序代码解释[关闭]