- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
这是我在 Scala 中实现的合并排序:
object FuncSort {
def merge(l: Stream[Int], r: Stream[Int]) : Stream[Int] = {
(l, r) match {
case (h #:: t, Empty) => l
case (Empty, h #:: t) => r
case (x #:: xs, y #:: ys) => if(x < y ) x #:: merge(xs, r) else y #:: merge(l, ys)
}
}
def sort(xs: Stream[Int]) : Stream[Int] = {
if(xs.length == 1) xs
else {
val m = xs.length / 2
val (l, r) = xs.splitAt(m)
merge(sort(l), sort(r))
}
}
}
它工作正常,似乎渐近地它也很好,但它比这里的 Java 实现慢得多(大约 10 倍)http://algs4.cs.princeton.edu/22mergesort/Merge.java.html并使用大量内存。是否有更快的功能性合并排序实现?显然,可以逐行移植 Java 版本,但这不是我想要的。
UPD:我已将 Stream
更改为 List
并将 #::
更改为 ::
和排序例程变得更快,只比 Java 版本慢三到四倍。但是我不明白为什么它不会因堆栈溢出而崩溃? merge
不是尾递归的,所有参数都经过严格评估...这怎么可能?
最佳答案
您提出了多个问题。我尽量按逻辑顺序回答:
你并没有真正问这个问题,但它导致了一些有趣的观察。
在 Stream 版本中,您在 merge
函数内使用 #::merge(...)
。通常这是一个递归调用,可能会导致足够大的输入数据堆栈溢出。但在这种情况下不是。运算符 #::(a,b)
在 class ConsWrapper[A]
中实现(存在隐式转换)并且是 cons.apply 的同义词[A](hd: A, tl: ⇒ Stream[A]): Cons[A]
。如您所见,第二个参数是按名称调用的,这意味着它是延迟计算的。
这意味着 merge
返回一个新创建的类型为 cons
的对象,它最终会再次调用 merge。换句话说:递归不是发生在栈上,而是发生在堆上。通常你有足够的堆。
使用堆进行递归是处理非常深的递归的好方法。但它比使用堆栈要慢得多。所以你用速度换取了递归深度。这就是使用 Stream
如此缓慢的主要原因。
第二个原因是,为了获得Stream
的长度,Scala必须具体化整个Stream
。但是在对 Stream
进行排序期间,它无论如何都必须具体化每个元素,所以这不会造成太大伤害。
当你把 Stream 换成 List 的时候,你确实是在用栈来递归。现在可能会发生堆栈溢出。但是对于排序,您通常具有 log(size)
的递归深度,通常是以 2
为底的对数。因此,要对 40 亿个输入项目进行排序,您需要大约 32 个堆栈框架。默认堆栈大小至少为 320k(在 Windows 上,其他系统具有更大的默认值),这为大量递归留出了空间,因此为大量输入数据进行了排序。
这取决于:-)
你应该使用栈,而不是堆来进行递归。你应该根据输入数据决定你的策略:
不要使用交换并使用你的缓存。如果可以,请使用可变数据结构并就地排序。我认为功能排序和快速排序不能很好地协同工作。要真正快速地进行排序,您将必须使用有状态操作(例如,可变数组上的就地合并排序)。
我通常在我的所有程序中尝试这样做:尽可能使用纯函数式风格,但在可行的情况下对小部分使用有状态操作(例如,因为它具有更好的性能,或者代码只需要处理很多状态并且变得很多当我使用 var
而不是 val
时,可读性更好。
关于algorithm - 快速函数归并排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18944524/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!