java-将PriorityQueue转换为排序数组的最佳方法
作者:互联网
我担心从包含数千个元素的Java PriorityQueue创建排序数组的不同样式. Java 8 docs说
If you need ordered traversal, consider using 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 doc的建议,但是除此之外,它在内存方面是否真的更有效,例如分配的临时结构更少等?
我认为流解决方案必须将流元素缓存在临时结构(数组?)中,然后对其进行排序,最后将排序后的元素复制到toArray()中分配的数组中.
当务之急是将堆元素缓存在新分配的数组中,然后对其进行排序.因此,这可能减少一个复制操作. (还有一个数组分配.这里与Collection.toArray(new T [size])与Collection.toArray(new T [0])的讨论是切线相关的.例如,请参阅here,了解为什么在OpenJDK上后者速度更快. )
那分选效率呢? Arrays.sort()的文档说
Temporary storage requirements vary from a small constant for nearly sorted input arrays to n/2 object references for randomly ordered input arrays
而Stream.sorted()的文档在这一点上保持沉默.因此,至少在可靠记录方面,命令式解决方案似乎具有优势.
但是还有什么要知道的吗?
解决方法:
从根本上讲,这两种变体都具有相同的功能,并且由于两者都是库预期用例中的有效解决方案,因此在选择算法或添加优化方面,没有理由为什么实现应优先于其他实现.
实际上,这意味着最昂贵的操作(排序)最终会在内部使用相同的实现方法. Stream实现的sorted(…)操作将所有元素缓冲到一个中间数组中,然后调用Arrays.sort(T [],int,int,Comparator <?super T>),它将委派给与您在第一个变体中使用的Arrays.sort(T [],Comparator <?super T&>)方法,目标是内部TimSort类中的sort方法. 因此,有关Arrays.sort的时间和空间复杂性的所有说明也适用于Stream.sort.但是,虽然存在性能差异.对于Java 10之前的OpenJDK实现,Stream无法将排序的内容与随后的toArray步骤融合在一起,无法将结果数组直接用于排序步骤.因此,当前,Stream变体承担着从用于排序的中间数组到传递给toArray的函数创建的最终数组的最后复制步骤.但是将来的实现可能会学到这个技巧,因此,这两个解决方案之间的相关性能将完全不同.
标签:java-stream,priority-queue,arrays,java,sorting 来源: https://codeday.me/bug/20191025/1926009.html