我在这里写了这两个方法来找到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
我的算法错了吗?我期待至少有类似的结果。
答案 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。