在整数,性能问题的数组中找到min max

时间:2017-08-10 21:09:51

标签: java algorithm performance

我在这里写了这两个方法来找到min和max。 #2基于此帖here的答案。

private static Pair classicMinMax(int[] elements) {
    int min = MAX_VALUE;
    int max = MIN_VALUE;

    for (int i = 0; i < elements.length; i++) {
        int e = elements[i];
        if (e < min) min = e;
        if (e > max) max = e;
    }
    return new Pair(min, max);

}

private static Pair divideAndConquer(int[] elements) {
    int min = MAX_VALUE;
    int max = MIN_VALUE;

    for (int i = 0; i < elements.length - 1; i += 2) {
        int a = elements[i];
        int b = elements[i + 1];

        if (a > b) {
            if (b < min) min = b;
            if (a > max) max = a;
        } else {
            if (a < min) min = a;
            if (b > max) max = b;
        }
    }

    if (elements.length % 2 != 0) {
        int lastElement = elements[elements.length - 1];
        if (lastElement < min) min = lastElement;
        if (lastElement > max) max = lastElement;
    }
    return new Pair(min, max);
}

如果我运行这样简单的基准测试:

@Test
public void timingsBoth() throws Exception {

    int size = 1000;

    for (int i = 1000; i < 10_000; i += 1000) {
        int arraySize = size * i;
        System.out.println("step is " + arraySize);

        List<Integer> list = new ArrayList<>(arraySize);
        int[] elements = new int[arraySize];
        for (int k = 0; k < arraySize; k++) {
            list.add(k);
        }

        Collections.shuffle(list);
        Integer[] integers = list.toArray(new Integer[0]);
        for (int k = 0; k < arraySize; k++) {
            elements[k] = integers[k];
        }

        long start = currentTimeMillis();
        classicMinMax(elements);
        long stop = currentTimeMillis();
        long result = stop - start;
        System.out.println("classic is " + result);

        start = currentTimeMillis();
        divideAndConquer(elements);
        stop = currentTimeMillis();
        result = stop - start;
        System.out.println("divideAndConquer is " + result);
    }
}

}

我通常会得到这样的结果:

step is 1000000 classic is 8 divideAndConquer is 11 step is 2000000 classic is 2 divideAndConquer is 5 step is 3000000 classic is 11 divideAndConquer is 17 step is 4000000 classic is 5 divideAndConquer is 10 step is 5000000 classic is 4 divideAndConquer is 16 step is 6000000 classic is 6 divideAndConquer is 14 step is 7000000 classic is 6 divideAndConquer is 18 step is 8000000 classic is 8 divideAndConquer is 20 step is 9000000 classic is 8 divideAndConquer is 24

我的算法错了吗?我期待至少有类似的结果。

1 个答案:

答案 0 :(得分:1)

好的,根据评论中的建议,我认为我做了更好的基准测试。 我使用的是Java Microbenchmark Harness。我之前从未使用它,因此我将测试基于这个方便的tutorial

我所做的是创建如下的JMH测试:

public class MinMaxBenchmark {

    @State(Scope.Benchmark)
    public static class MyState {

        int arraySize = 50_0000;
        int[] elements = new int[arraySize];

        @Setup(Level.Trial)
        public void doSetup() {
            List<Integer> list = new ArrayList<>(arraySize);
            for (int k = 0; k < arraySize; k++) {
                list.add(k);
            }
            Collections.sort(list);
            Integer[] integers = list.toArray(new Integer[0]);
            for (int k = 0; k < arraySize; k++) {
                elements[k] = integers[k];
            }

        }
    }


    @Benchmark @BenchmarkMode(Mode.SampleTime   ) @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public Pair classic(MyState state) {
        return classicMinMax(state.elements);
    }
    @Benchmark @BenchmarkMode(Mode.SampleTime) @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public Pair divide(MyState state) {
        return divideAndConquer(state.elements);
    }

}

我特别注意在基准测试之外创建数组(输入数据),使用@State方法创建@Setup进行初始化。比我写的@Benchmark方法。我在返回结果时非常小心,因此可以避免死代码(它在教程中都是如此)。

通过这个设置,我进行了几次试验。这是最后一次尝试:

Benchmark Mode Cnt Score Error Units MinMaxBenchmark.classic sample 994028 0.202 ± 0.001 ms/op MinMaxBenchmark.classic:classic·p0.00 sample 0.153 ms/op MinMaxBenchmark.classic:classic·p0.50 sample 0.180 ms/op MinMaxBenchmark.classic:classic·p0.90 sample 0.259 ms/op MinMaxBenchmark.classic:classic·p0.95 sample 0.311 ms/op MinMaxBenchmark.classic:classic·p0.99 sample 0.409 ms/op MinMaxBenchmark.classic:classic·p0.999 sample 0.567 ms/op MinMaxBenchmark.classic:classic·p0.9999 sample 0.942 ms/op MinMaxBenchmark.classic:classic·p1.00 sample 2.617 ms/op MinMaxBenchmark.divide sample 1226029 0.164 ± 0.001 ms/op MinMaxBenchmark.divide:divide·p0.00 sample 0.126 ms/op MinMaxBenchmark.divide:divide·p0.50 sample 0.149 ms/op MinMaxBenchmark.divide:divide·p0.90 sample 0.201 ms/op MinMaxBenchmark.divide:divide·p0.95 sample 0.230 ms/op MinMaxBenchmark.divide:divide·p0.99 sample 0.327 ms/op MinMaxBenchmark.divide:divide·p0.999 sample 0.522 ms/op MinMaxBenchmark.divide:divide·p0.9999 sample 0.945 ms/op MinMaxBenchmark.divide:divide·p1.00 sample 3.199 ms/op

实际上划分只会在 p1.00 上失败(我需要找到意思)。

所以我猜这是我处理基准测试的问题。

感谢您在评论中提供的帮助,尤其是@alfasin。