在列表中给出百万个数字。如何以最小的时间复杂度将每个元素按常量变化

时间:2016-05-11 06:13:40

标签: java multithreading arraylist

我编写了一个java程序,它通过一些常量很清楚列表中的每个数字。以下是该计划。我创建了一个myNewNumbers列表来存储那些多了多少的数字。以下是我的疑惑

有没有更好的方法以最短的时间复杂度来写这个? 目前在我的for循环中有10个元素。如果用户想要为100万个元素进行处理,该如何处理? 我是多线程的初学者。我如何确保它在mutithreading中工作

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MultiplyHugeNumber {

    static List<Integer> mynumbers;
    static List<Integer> myNewnumbers;
    static Integer MUTIPLY_ELEMENT=2;

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        mynumbers= new ArrayList<Integer>();
        for (int i = 0; i < 10; i++) {
            mynumbers.add(i);
        }

        System.out.println(Arrays.toString(mynumbers.toArray()));
        myNewnumbers= new ArrayList<>();
        for (Integer mynumber : mynumbers) {
            myNewnumbers.add(mynumber*MUTIPLY_ELEMENT);

        }

        System.out.println(Arrays.toString(myNewnumbers.toArray()));
    }

 o/p:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

3 个答案:

答案 0 :(得分:2)

如果您有一百万个元素,并且需要将每个元素乘以常数,那么您将需要执行一百万个操作。没有办法解决它 - 它是O(n)。

那就是说,创建列表可以是O(1)(常数时间),如果你对一个懒惰评估的列表没问题。番石榴的Lists.transform就是这样做的:

List<Integer> myNumbers = ...
List<Integer> myNewNumbers = Lists.transform(myNumbers, i -> i * MULTIPLY_ELEMENT);

这不会减少进行所有乘法所需的总时间;实际上,它总体上可能需要一些更多时间,因为JVM更难以优化。如果多次访问同一元素,它也会变慢,因为每次执行转换时都会应用。也就是说,它不太可能在你注意到的数量上变慢。

此方法还带有限制,您无法将新元素添加到转换列表中(如JavaDocs中所述)。但是,根据您的情况,快速创建初始列表可能还有其他好处。

答案 1 :(得分:1)

(@STaefi的信用)将输入值列表乘以常量值的时间复杂度为O(n)。这种复杂性与多线程实现无关。

您的程序:将一个数字列表乘以一个常数,属于所谓的"Embarrassingly Parallel"问题类别:

  

“[...]需要很少或根本不需要努力将问题分成若干并行任务[...]”

输入列表中的每个项目都可以与常量相乘,而不考虑任何其他输入项目或全局状态。

有多种方法可以并行化给定任务。请注意,设置线程的开销对于少量输入值可能不值得,或者在此特定示例中根本不值得。

使用Java 8流的示例:

 mynumbers.parallelStream()
          .map(in -> in * MUTIPLY_ELEMENT)
          .collect(Collectors.toList());

答案 2 :(得分:0)

这是100%的过早优化,在这种情况下很可能没有值得优化。

然而......在学术上说“你需要在这里问自己一个问题,即结果的顺序是否重要?

如果没有,那么使用Streams,这很简单,这是一个包含100个数字的例子:

    Integer MUTIPLY_ELEMENT = 2;
    List<Integer> resultNumbers = IntStream.range(0,100)
            .parallel()
            .map(i->i*MUTIPLY_ELEMENT)
            .boxed()
            .collect(Collectors.toList());

如果您确实关心订购,但仍希望获得并行处理的好处,您可以利用您的操作(乘以2)足够简单以至于得到的数字仍然在同一个相对的事实“自然”订单,只需在sorted()调用后在流上调用map()即可。但是,排序操作可能需要的时间与单线程一样。

另外,要明白,这不是一个“现实世界”的场景,你几乎不会遇到像这样的实际问题。希望你只是试图了解一般的并行性,因为在尝试单线程模型并且证明不足之前,你实际上从未真正想要进行这种类型的优化。