当前位置: 首页 > 知识库问答 >
问题:

Java:如何优化大数组求和

谭翔
2023-03-14
//array could be Integer.MAX_VALUE length
private long canocicalSum(int[] array) { 
    int sum = 0;
    for (int i = 0; i < array.length; i++)
        sum += array[i];
    return sum;
}

问题1[主]:是否可以优化canonicalsum

我尝试过:避免使用非常大的数字的操作。所以我决定使用辅助数据。例如,我将array1[100]转换为array2[10],其中array2[I]=array1[I]+array1[I+1]+array1[I+9]

private long optimizedSum(int[] array, int step) {
    do {
        array = sumItr(array, step);
    } while (array.length != 1);
    return array[0];
}

private  int[] sumItr(int[] array, int step) {
    int length = array.length / step + 1;
    boolean needCompensation = (array.length % step == 0) ? false : true;
    int aux[] = new int[length];
    for (int i = 0, auxSum = 0, auxPointer = 0; i < array.length; i++) {
        auxSum += array[i];
        if ((i + 1) % step == 0) {
            aux[auxPointer++] = auxSum;
            auxSum = 0;
        }
        if (i == array.length - 1 && needCompensation) {
            aux[auxPointer++] = auxSum;
        }
    }
    return aux;
}

问题:但是canonicalsum似乎比optimizedsum快十倍。这里是我的测试:

@Test
public void sum_comparison() {
    final int ARRAY_SIZE = 100000000;
    final int STEP = 1000;
    int[] array = genRandomArray(ARRAY_SIZE);

    System.out.println("Start canonical Sum");
    long beg1 = System.nanoTime();
    long sum1 = canocicalSum(array);
    long end1 = System.nanoTime();
    long time1 = end1 - beg1;
    System.out.println("canon:" + TimeUnit.MILLISECONDS.convert(time1, TimeUnit.NANOSECONDS) + "milliseconds");

    System.out.println("Start optimizedSum");
    long beg2 = System.nanoTime();
    long sum2 = optimizedSum(array, STEP);
    long end2 = System.nanoTime();
    long time2 = end2 - beg2;
    System.out.println("custom:" + TimeUnit.MILLISECONDS.convert(time2, TimeUnit.NANOSECONDS) + "milliseconds");

    assertEquals(sum1, sum2);
    assertTrue(time2 <= time1);
}

private int[] genRandomArray(int size) {
    int[] array = new int[size];
    Random random = new Random();
    for (int i = 0; i < array.length; i++) {
        array[i] = random.nextInt();
    }
    return array;
}

共有1个答案

彭琛
2023-03-14

问题1[主]:是否可能优化CanonicalSum?

是的,是的。但我不知道是什么因素造成的。

您可以做的一些事情是:

    null
for (int x = 0; x < 100; x++)
{
    delete(x);
}
for (int x = 0; x < 100; x+=5)
{
    delete(x);
    delete(x+1);
    delete(x+2);
    delete(x+3);
    delete(x+4);
}

这里可以看到多线程方法的数学运算的实现。

Java7中引入的fork/join框架的示例实现基本上完成了上面的分而治之算法所做的工作:

public class ForkJoinCalculator extends RecursiveTask<Double> {

   public static final long THRESHOLD = 1_000_000;

   private final SequentialCalculator sequentialCalculator;
   private final double[] numbers;
   private final int start;
   private final int end;

   public ForkJoinCalculator(double[] numbers, SequentialCalculator sequentialCalculator) {
     this(numbers, 0, numbers.length, sequentialCalculator);
   }

   private ForkJoinCalculator(double[] numbers, int start, int end, SequentialCalculator sequentialCalculator) {
     this.numbers = numbers;
     this.start = start;
     this.end = end;
     this.sequentialCalculator = sequentialCalculator;
   }

   @Override
   protected Double compute() {
     int length = end - start;
     if (length <= THRESHOLD) {
         return sequentialCalculator.computeSequentially(numbers, start, end);
     }
     ForkJoinCalculator leftTask = new ForkJoinCalculator(numbers, start, start + length/2, sequentialCalculator);
     leftTask.fork();
     ForkJoinCalculator rightTask = new ForkJoinCalculator(numbers, start + length/2, end, sequentialCalculator);
     Double rightResult = rightTask.compute();
     Double leftResult = leftTask.join();
     return leftResult + rightResult;
  }
}

在这里,我们开发了一个recursivetask来拆分一个数组,直到子数组的长度不低于给定的阈值。此时,子数组将按顺序进行处理,并对其应用由以下接口定义的操作

public interface SequentialCalculator {
  double computeSequentially(double[] numbers, int start, int end);
}
public static double varianceForkJoin(double[] population){
   final ForkJoinPool forkJoinPool = new ForkJoinPool();
   double total = forkJoinPool.invoke(new ForkJoinCalculator(population, new SequentialCalculator() {
     @Override
     public double computeSequentially(double[] numbers, int start, int end) {
       double total = 0;
       for (int i = start; i < end; i++) {
         total += numbers[i];
       }
       return total;
     }
  }));
  final double average = total / population.length;
  double variance = forkJoinPool.invoke(new ForkJoinCalculator(population, new SequentialCalculator() {
    @Override
    public double computeSequentially(double[] numbers, int start, int end) {
      double variance = 0;
      for (int i = start; i < end; i++) {
        variance += (numbers[i] - average) * (numbers[i] - average);
      }
      return variance;
    }
 }));
 return variance / population.length;
}
 类似资料:
  • 本文向大家介绍如何进行大表优化?相关面试题,主要包含被问及如何进行大表优化?时的应答技巧和注意事项,需要的朋友参考一下 当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下: 1. 限定数据的范围 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内; 2. 读/写分离 经典的数据库拆分方案,主库负责写,从库

  • 我是本地Android开发者,我开始使用Flatter SDK。我开发了一个简单的应用程序,遵循官方的颤振文件。但是我发现调试应用的大小是46MB,对于这个简单的应用来说太大了。有没有办法优化应用程序的大小?因为Flatter应用程序的大小比原生Android应用程序大。

  • 这样一堆 if 合理吗?后面还会加判断,会更多。 再拆分的话感觉不太好,有更好的方法吗?

  • 给定一个正负整数数组,如何找到长度在和之间的最大和子数组(连续子数组)? 例如:如果数组是 我的方法: 我不太确定如何处理这个问题。我想也许是滑动窗口+Kadane的组合。我听说前缀和+滑动窗口可能是一个可能的解决方案,但我不确定如何实现它。

  • 主要内容:业务场景,如何通过缓存优化查询接口,基于大数据离线平台进行缓存预热,本地缓存框架:Ehcache今天给大家来分享一个知识,那就是平时我们开发系统的时候,如何运用 Ehcache 这款本地缓存框架,把我们的查询性能大幅度提升优化,甚至让很多查询操作性能提升到 100 倍以上,下面就来讲讲这个话题。 业务场景 首先给大家引入一个场景,就是假设咱们写的一套 Java 系统要跑一个几百行的大 SQL 从 MySQL 里查询数据,这个查询是不是会速度非常的慢? 那肯定是了,这种几百行大 SQL

  • 我有这样两个数组需要循环匹配出结果,如果没有用splice,出来的结果是正确的。但是我想优化下循环查找的代码,发现结果不对了 后来我又试了下splice函数 发现果然结果和我预想的不同了 请问上面的代码我该如何降低每次的循环量?