【问题标题】:Best way to convert a PriorityQueue to a sorted array将 PriorityQueue 转换为排序数组的最佳方法
【发布时间】:2018-12-07 07:24:31
【问题描述】:

我关心从包含几千个元素的 Java PriorityQueue 创建排序数组的不同样式。 Java 8 docs

如果您需要有序遍历,请考虑使用 Arrays.sort(pq.toArray())。

不过,我确实喜欢流式 API,所以我最初拥有的是

Something[] elems = theHeap.stream().sorted(BY_CRITERION.reversed())
                       .toArray(Something[]::new);

(其中BY_CRITERION 是 PriorityQueue 的自定义比较器,我确实想要它的相反顺序。)与以下相比,使用此成语有什么缺点:

Something[] elems = theHeap.toArray(new Something[0]);
Arrays.sort(elems, BY_CRITERION.reversed());

后一个代码显然更直接地遵循 API 文档建议,但除此之外,它在内存方面是否真的更有效,例如分配的临时结构更少等?

我认为流式解决方案必须将流元素缓冲在一个临时结构(数组?)中,然后对它们进行排序,最后将排序后的元素复制到toArray()中分配的数组中。

虽然命令式解决方案会将堆元素缓冲在新分配的数组中,然后对它们进行排序。所以这可能会少一个复制操作。 (还有一个数组分配。Collection.toArray(new T[size])Collection.toArray(new T[0]) 的讨论与此处相关。例如,请参阅 here 了解为什么在 OpenJDK 上后者更快。)

那么分拣效率呢? Arrays.sort() 的文档说

临时存储要求从几乎排序的输入数组的小常数到随机排序的输入数组的 n/2 对象引用不等

Stream.sorted() 的文档在这一点上保持沉默。因此,至少在可靠记录方面,命令式解决方案似乎具有优势。

但是还有什么要知道的吗?

【问题讨论】:

  • 不使用流几乎总是性能更好的选择(除非您使用 .parallel() 和拥有数百万条目大小的数据)
  • 如果优先队列已经按照排序顺序为您提供了元素,为什么还要再次排序。
  • BY_CRITERION.reversed()作为比较器初始化priorityQueue
  • @SleimanJneidi 因为它不是。只有 peek() 和 poll() 尊重比较器。没有有序遍历的方法。这是在文档中指定的。
  • @Sebastian 关于流的要点是它们表达了它们的什么,而不是如何它们这样做。在内部,他们使用了很多对象,在这里和那里创建新的引用。看起来很好。但就性能而言,正如串行所说的那样,至少不是最佳选择。而使用数组方法只创建一个数组,然后对其进行排序。不再对其执行任何操作。这就是它更快的原因

标签: java arrays sorting java-stream priority-queue


【解决方案1】:

从根本上说,两种变体的作用相同,并且由于它们都是库预期用例中的有效解决方案,因此在选择算法或添加优化方面,没有理由让实现更偏爱另一种。

实际上,这意味着最昂贵的操作,即排序,最终会在内部使用相同的实现方法。 Stream 实现的sorted(…) 操作将所有元素缓冲到一个中间数组中,然后调用Arrays.sort(T[], int, int, Comparator<? super T>),它将委托给与您在第一个变体中使用的方法Arrays.sort(T[], Comparator<? super T>) 相同的方法,目标是排序方法在内部 TimSort 类中。

因此,关于Arrays.sort 的时间和空间复杂性的所有内容也适用于Stream.sort。但是,尽管存在性能差异。对于 Java 10 之前的 OpenJDK 实现,Stream 无法将sorted 与后续的toArray 步骤融合,以直接使用结果数组进行排序步骤。因此,目前,Stream 变体具有从用于排序的中间数组到由传递给toArray 的函数创建的最终数组的最终复制步骤。但是未来的实现可能会学习这个技巧,那么这两种解决方案之间不会有任何相关的性能差异。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 2013-10-30
    • 2018-04-21
    • 1970-01-01
    • 2021-11-17
    • 2023-04-08
    • 2017-12-19
    • 1970-01-01
    相关资源
    最近更新 更多