栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

快速功能合并排序

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

快速功能合并排序

您提出了多个问题。我尝试按照逻辑顺序回答它们:

流版本中没有堆栈溢出

您并没有真正问过这个问题,但是它带来了一些有趣的发现。

在Stream版本中,您正在函数

#::merge(...)
内部使用
merge
。通常,这将是递归调用,并可能导致堆栈溢出,无法容纳足够大的输入数据。但在这种情况下不是。运算符
#::(a,b)
在中实现
classConsWrapper[A]
(存在隐式转换),并且是的同义词
cons.apply[A](hd: A, tl: ⇒ Stream[A]):Cons[A]
。如您所见,第二个参数是按名称调用的,这意味着它是惰性计算的。

这意味着

merge
返回一个新创建的类型的对象,
cons
该对象最终将再次调用merge。换句话说:递归不是在堆栈上发生,而是在堆上发生。通常,您有很多堆。

使用堆进行递归是处理非常深的递归的好方法。但这比使用堆栈要慢得多。因此,您将速度与递归深度进行了交换。这是主要原因,使用

Stream
速度如此之慢。

第二个原因是,为了获得长度

Stream
,Scala必须实现整体
Stream
。但是在排序过程中
Stream
,无论如何都必须实现每个元素,因此这不会造成太大的伤害。

列表版本中没有堆栈溢出

当更改Stream for
List时,实际上是在使用堆栈进行递归。现在可能会发生堆栈溢出。但是通过排序,您的递归深度

log(size)
通常为base的对数
2
。因此,要对40亿个输入项目进行分类,您将需要大约32个堆栈帧。默认堆栈大小至少为320k(在Windows上,其他系统具有更大的默认值),因此有很多递归空间,因此可以对许多输入数据进行排序。

更快的功能实现

这取决于 :-)

您应该使用堆栈,而不要使用堆进行递归。您应该根据输入数据决定策略:

  1. 对于小数据块,请使用一些简单算法将它们排序到位。算法的复杂性不会给您带来麻烦,并且通过将所有数据都缓存在缓存中可以提高性能。当然,对于给定的大小,您仍然可以手动编写代码分类网络。
  2. 如果您有数字输入数据,则可以使用基数排序并按处理器或GPU上的矢量单位处理功(可以在GPU Gems中找到更复杂的算法)。
  3. 对于中型数据块,可以使用分而治之的策略将数据拆分为多个线程(仅当您具有多个内核时!)
  4. 对于巨大的数据块,请使用合并排序并将其拆分为适合内存的块。如果需要,可以在网络上分发这些块并在内存中排序。

不要使用swap并使用缓存。如果可以并使用适当的位置,请使用可变数据结构。我认为功能排序和快速排序不能很好地协同工作。为了使排序真正快速,您将必须使用有状态操作(例如,对可变数组进行就地归并排序)。

我通常在所有程序上都尝试这样做:尽可能使用纯函数样式,但在可行的情况下对小部分使用有状态的操作(例如,因为它具有更好的性能,或者代码只需要处理很多状态,而在我用

var
s代替
val
s)。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/616961.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号