什么';s Java Stream distinct()的时间复杂度。Sorded()?

什么';s Java Stream distinct()的时间复杂度。Sorded()?,java,java-stream,Java,Java Stream,每次我接受编码面试时,我总是避免使用Java流,因为我不能很好地分析时间复杂性 例如:在我的日常工作中,我可能会这样写: Arrays.stream(a).distinct().sorted().toArray(); 获取唯一编号并对其进行排序 但我很好奇时间的复杂性会是。。?是distinct()。排序后将成为嵌套循环吗 我需要把它们分开吗 int[] arr = Arrays.stream(a).distinct().toArray(); Arrays.stream(arr).sorted

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

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

Arrays.stream(a).distinct().sorted().toArray();
获取唯一编号并对其进行排序

但我很好奇时间的复杂性会是。。?是distinct()。排序后将成为嵌套循环吗

我需要把它们分开吗

int[] arr = Arrays.stream(a).distinct().toArray();
Arrays.stream(arr).sorted().toArray();
所以有时候当我面试的时候,我会用set来区分,然后对它们进行排序。。。。 但我真的想写一个干净的代码


如果有人能帮忙的话!谢谢大家!

没有明确的语句是可能的,因为您是根据接口开发的,并且规范没有规定特定的排序算法

对于泛型
,我们必须假设一个比较排序,它是任何算法都无法避免的

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

distinct()
的时间复杂度为O(n),因为它只是检查添加到
HashSet
中是否成功。将O(n)与O(n logn)相结合会导致O(n logn)的总体复杂性。也许面试官把时间的复杂性组合错了

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

这种性能差异不包括在时间复杂度中,这两种方法的时间复杂度仍然相同。但是如前所述,对于原始类型的流,可以使用具有不同时间复杂度的不同算法

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

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



对于基本流,这只适用于Java 9+。如前所述,
distinct()
没有原语专门化,它的实现方式类似于
boxed().distinct().mapToInt(i->i)
,而在Java 8中,
boxed()
被实现为
mapToObj(Integer::valueOf)
,它会丢失有关排序输入的信息,正如。

的最后一节中所解释的,没有明确的语句,因为您是根据接口开发的,并且规范没有强制要求特定的排序算法

对于泛型
,我们必须假设一个比较排序,它是任何算法都无法避免的

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

distinct()
的时间复杂度为O(n),因为它只是检查添加到
HashSet
中是否成功。将O(n)与O(n logn)相结合会导致O(n logn)的总体复杂性。也许面试官把时间的复杂性组合错了

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

这种性能差异不包括在时间复杂度中,这两种方法的时间复杂度仍然相同。但是如前所述,对于原始类型的流,可以使用具有不同时间复杂度的不同算法

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

请注意,上面的语句假设一个终端操作,就像您的示例的
toArray
那样