Java Stream的distinct().sorted()的时间复杂度是多少?

Tim*_*Lin 4 java java-stream

每次当我接受编码面试时,我总是避免使用Java流,因为我不能很好地分析时间复杂度。

例如:在日常工作中,我可能会这样写:

Arrays.stream(a).distinct().sorted().toArray();
Run Code Online (Sandbox Code Playgroud)

获取唯一编号并对它们进行排序。

但我很好奇时间复杂度是......?is unique().sorted 会变成嵌套循环吗?

我需要把它们分开吗?

int[] arr = Arrays.stream(a).distinct().toArray();
Arrays.stream(arr).sorted().toArray();
Run Code Online (Sandbox Code Playgroud)

所以有时当我接受采访时,我会使用 set 来区分然后对它们进行排序......但我真的想编写一个干净的代码......

如果有人可以帮忙的话!谢谢你!

Hol*_*ger 6

没有可能的明确声明,因为您正在针对接口进行开发,并且规范没有强制要求特定的排序算法。

\n

对于泛型Stream,我们必须假设一种比较排序,任何算法都无法避免其 O(n log n) 的最坏情况。

\n

但是您的示例使用IntStream原则上可以使用计数排序或类似排序,具有 O(n) 。这在参考实现的实践中不会发生,因为具有更好的最坏情况时间复杂度并不一定会在实践中带来更好的性能,并且元素的最大数量仅限于 JVM\xe2\x80\ x99s 最大数组大小。

\n

时间复杂度distinct()为O(n),因为它只是检查添加到a是否HashSet成功。将 O(n) 与 O(n log n) 结合起来会导致整体复杂度为 O(n log n)。也许面试官错误地结合了时间复杂度。

\n

但这是一个很好的例子,证明时间复杂度并不等于性能。当您使用 时sorted().distinct(),该distinct()操作将利用传入元素的排序性质HashSet,这使得无需在幕后构建\xc2\xb9。由于参考实现没有设置原始值,因此消除了大量装箱开销。另一方面,使用distinct().sorted()可以减少要排序的元素数量,但它需要比总流元素少得多的不同元素才能获得回报。

\n

这种性能差异并未被时间复杂度所涵盖,这两种方法的时间复杂度仍然相同。但如上所述,对于原始类型的流,具有不同时间复杂度的不同算法是可能的。

\n

但有一件事,我们可以肯定地说。当您将操作拆分为两个流操作时,例如从第一个操作请求结果数组并将其传递给Arrays.stream再次,底层实现不可能在下一个操作中利用有关前一个操作的知识。

\n

请注意,上面的语句假定像您的 example\xe2\x80\x99s 这样的终端操作toArray会消耗所有元素,并需要维护生成的遭遇顺序。对于其他短路或无序终端操作,总体时间复杂度可能会发生变化,例如,sorted().findFirst()可能会被优化为等效的min(),或者对于无序终端操作可以消除排序步骤,例如sum()。在当前的参考实现中不会发生这种情况,但是,正如前面所说,您\xe2\x80\x99 正在针对接口进行编程。

\n
\n

\xc2\xb9 对于原始流,这只适用于 Java\xc2\xa09+。如前所述, 没有原始专门化distinct(),它的\xe2\x80\x99s 实现类似于boxed().distinct().mapToInt(i -> i)Java\xc2\xa08 中的 和 ,boxed()其实现为mapToObj(Integer::valueOf)丢失有关排序输入的信息,如本答案的最后一节所述。

\n