【问题标题】:Explanation of quicksort in APLAPL中快速排序的解释
【发布时间】:2020-06-18 20:42:42
【问题描述】:

我正在尝试理解 APL 中的经典快速排序:

Q←{1≥≢⍵:⍵ ⋄ S←{⍺⌿⍨⍺ ⍺⍺ ⍵} ⋄ ⍵((∇<S)⍪=S⍪(∇>S))⍵⌷⍨?≢⍵}

有些东西我不明白,有些风格选择让我很困扰,所以我将把它们全部列出来。我希望有人能给我解释一下。

  1. 我知道在{ } defn 中, 是左参数, 是右参数。 S←{⍺⌿⍨⍺ ⍺⍺ ⍵} 中的 ⍺⍺ 是什么?同样,是否有⍵⍵S 中的 是指Sleft 参数 还是Qleft 参数?

我的猜测是S 中的 指的是S 的左参数。 ⍺⍺ 指的是封闭函数(即Q的)。

  1. 为什么要大量使用通勤 ()?代码是不是更清楚地写成:
Q←{1≥≢⍵:⍵ ⋄ S←{(⍺ ⍺⍺ ⍵)⌿⍺} ⋄ ⍵((∇<S)⍪=S⍪(∇>S))⍵[?≢⍵]}

我能想到的使用通勤的唯一用途是减少括号 ()[] 的使用,但这似乎不值得失去易读性。我在这里错过了一些“APL方式”吗?

  1. 这实际上并不是在执行快速排序,是吗?快速排序被定义为就地。但是,我对 APL 语义的理解是,这段代码实际上在递归子调用上构建了新数组,并使用 将它们连接起来。确实,这是same criticism that is levelled at Haskell's quicksort。我在 APL 语义中是否遗漏了一些东西来告知此操作是“就地”完成的?请注意,我对“足够聪明的编译器”参数不感兴趣,因为数组分析从根本上具有挑战性。如果 APL 编译器确实将其转化为就地算法,我会非常重视有关它如何执行此分析的详细信息 --- 这真是一项成就!

  2. 为什么要使用≢⍵来查找维度大小?为什么不⍴⍵?一般来说,我发现人们使用 而非 来查询沿最外层维度的大小,即使函数工作的唯一情况是在一维中。同样,我认为我在 APL 方式中缺少某些东西。

非常感谢。

【问题讨论】:

    标签: quicksort in-place apl dyalog


    【解决方案1】:
    1. 我知道在{ } defn 中, 是左参数, 是右参数。 S←{⍺⌿⍨⍺ ⍺⍺ ⍵} 中的 ⍺⍺ 是什么?同样,有⍵⍵吗?

    S←{⍺⌿⍨⍺ ⍺⍺ ⍵} 被称为 dop。类似于 dfn 是用户定义的函数,dop 是用户定义的运算符,其行为类似于 ¨

    其语义总结:

    • 如果一个 dop 只提到 ⍺⍺(而不是 ⍵⍵),它就会变成一元运算符,您可以将其用作 x (m S) y
    • 如果一个dop提到⍵⍵,它就变成了一个二元运算符,你可以用它作为x (m S n) y
    • 在这两种情况下,⍺⍺(其值为m)和⍵⍵(其值为n)可以是数组或函数。
    • 您也可以决定不在 dop 的正文中使用,在这种情况下,您可以将其称为(m S) y(m S n) y,省略左侧的参数
    • m 称为左操作数n 称为右操作数。这些与左参数 (x) 和右参数 (y) 不同。

    在你的例子中,S 只提到了⍺⍺,所以它被称为x (m S) y。如果您像1 2 3 &gt;S 2 一样调用S,它将评估为1 2 3⌿⍨1 2 3 &gt; 2,这将是单个3。

    S中的是指S的左参数还是Q的左参数?

    S 的主体内,所有由 组成的字符都指的是S 的参数/操作数。 Q 的原始参数是不可见的(除非先将它们分配给变量,在这种情况下它们作为变量名可见)。

    1. 为什么要大量使用通勤 ()?

    我相信这主要是一种风格选择。我也更喜欢编写带括号的代码而不是在生产代码中使用它,除非该用法很容易被识别为 APL 习惯用法。我确实写了例如3÷⍨whatever 而不是 (whatever)÷3 用于除以常数。

    1. 这实际上并不是在执行快速排序,是吗?

    你是对的。正如您已经提到的,Quicksort 旨在就地运行以真正成为 Quick (TM)。 APL 可以做内存预分配和数组共享,以减少一些内存复制和分配,但是在创建三个子数组(元素小于/等于/大于枢轴)时,至少有一些副本是不可避免的,并且稍后连接。

    需要注意的一点是,与 Haskell 不同,APL 确实有就地赋值,看起来像 x[i]←v。如果要在 APL 中正确实现 Quicksort,则必须像在 C 中那样编写代码(将索引传递给递归调用等)。

    1. 为什么要使用≢⍵来查找维度大小?为什么不⍴⍵

    被称为“计数”,而 被称为“形状”。 总是返回一个标量值,而 返回一个向量(如果给定向量参数,它将是一个长度为一的向量)。虽然标量和长度为一的向量在大多数情况下表现相同,但它们不同的东西,例如1≡,1 是假的。

    我相信区分两者是一个好习惯,尽可能使用标量而不是长度为一的向量。一个值得注意的例外是当您需要一个显式封闭的数组(不能封闭标量)时。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      • 2015-10-16
      • 1970-01-01
      • 2022-10-06
      • 2020-08-14
      • 2014-10-10
      • 2016-12-23
      相关资源
      最近更新 更多