简体   繁体   English

克服堆溢出问题

[英]Overcoming heap overflow issues

I tried to solve problems from Project Euler. 我试图解决Project Euler的问题。 I know my method would work logically (it returns answers to the small scale problem almost instantly). 我知道我的方法会在逻辑上起作用(它几乎立即返回小规模问题的答案)。 However, it scales horribly. 然而,它可怕地扩展。 I already attempted changing the .ini file, but to no avail. 我已经尝试更改.ini文件,但无济于事。

Here's my code: 这是我的代码:

public class Number28 {

    static int SIZE = 101; //this should be an odd number, i accidentally posted 100
    /**
     * @param args
     */
    public static void main(String[] args) {
        double start = System.currentTimeMillis();
        long spiral[][]= spiral(SIZE);
        long sum = 0;
        for(int i = 0; i < SIZE; i++)
        {
            sum += spiral[i][i];
            sum += spiral[i][SIZE - 1 - i];
        }
        System.out.println(sum - 1);
        double time = System.currentTimeMillis() - start;
        System.out.println(time);

    }
    public static long[][] spiral(int size){
        long spiral[][]= new long[size][size];
        if(size == 1){
            spiral[0][0] = 1;
            return spiral;
        }
        else{
            long subspiral[][]= new long[size - 2][size - 2];
            subspiral = spiral(size - 2);
            for(int r = 0; r < size - 2; r++){
                for(int c = 0; c < size - 2; c++){
                    spiral[r + 1][c + 1] = subspiral[r][c];
                }
            }
            long counter = subspiral[0][size - 3];
            for(int r = 1; r < size ; r++){
                counter++;
                spiral[r][size - 1] = counter;
            }
            for(int c = size - 2; c >= 0; c--){
                counter++;
                spiral[size - 1][c] = counter;
            }
            for(int r = size - 2 ; r >= 0 ; r--){
                counter++;
                spiral[r][0] = counter;
            }
            for(int c = 1; c < size ; c++){
                counter++;
                spiral[0][c] = counter;
            }

            return spiral;
        }
    }
}

Here's the edited code, worked like a gem: 这是编辑过的代码,像gem一样工作:

public class Number28 {
    static int SIZE = 1001;
    static long spiral[][]= new long[SIZE][SIZE];

    /**
     * @param args
     */
    public static void main(String[] args) {
        double start = System.currentTimeMillis();
        long spiral[][]= spiral(SIZE);
        long sum = 0;
        for(int i = 0; i < SIZE; i++)
        {
            sum += spiral[i][i];
            sum += spiral[i][SIZE - 1 - i];
        }
        System.out.println(sum - 1);
        double time = System.currentTimeMillis() - start;
        System.out.println(time);

    }
    public static long[][] spiral(int size){
        if(size == 1){
            spiral[SIZE / 2][SIZE / 2] = 1;
            return spiral;
        }
        else{
            long subspiral[][]= spiral(size - 2);
            int edge = (SIZE - size) / 2;
            long counter = subspiral[edge + 1][edge + size - 2];

              for(int r = 1; r < size ; r++){
                  counter++;
                  spiral[edge + r][edge + size - 1] = counter;
          }
          for(int c = size - 2; c >= 0; c--){
                  counter++;
                  spiral[edge + size - 1][edge + c] = counter;
          }
          for(int r = size - 2 ; r >= 0 ; r--){
                  counter++;
                  spiral[edge + r][edge] = counter;
          }
          for(int c = 1; c < size ; c++){
                  counter++;
                  spiral[edge][edge + c] = counter;
          }
            return spiral;
        }
    }
}

As a general piece of Project Euler advice, if your solution doesn't scale, there's almost certainly a better way to solve it. 作为Project Euler建议的一般部分,如果您的解决方案无法扩展,那么几乎可以肯定有更好的方法来解决它。 If you've used the same type of solution on an earlier problem you can go through the posts from other users on the earlier question to get ideas for solving the problem in different ways. 如果您在早期问题上使用了相同类型的解决方案,则可以通过前面问题的其他用户发布帖子,以获得以不同方式解决问题的想法。

Not familiar with the Euler problems, but the horror appears to be your continual allocation and re-allocation of what are basically throwaway intermediate spirals, as you call down recursively to the base case. 不熟悉欧拉问题,但恐怖似乎是你不断分配和重新分配什么是基本上一次性的中间螺旋,因为你递归地调用基本情况。

Restructure so that you allocate your full spiral up front. 重组,以便您预先分配完整的螺旋。 Then call your recursive function, passing your full spiral in as a parameter by reference, along with a "level" parameter, which will change with each recursive call. 然后调用递归函数,通过引用将完整螺旋作为参数传递,同时传递“level”参数,该参数随每次递归调用而变化。 Eg, initial call is with 100x100 spiral and level 100; 例如,初始呼叫是100x100螺旋和100级; next (recursive) call is with same spiral, by reference, and level 98. Operations within the function will all be done on the one-and-only-allocated spiral. next(递归)调用具有相同的螺旋,通过引用和级别98.函数内的操作将全部在唯一分配的螺旋上完成。

In a nutshell: allocate your data structure once, even if you operate on that data structure recursively. 简而言之:即使您以递归方式操作该数据结构,也要分配一次数据结构。

Here is a simplified solution that doesn't store a matrix: 这是一个不存储矩阵的简化解决方案:

public class P28 {

    private final static int N = 1001;

    public static void main(String[] args) {

        int limit = (N + 1) / 2;
        int sum = -3;
        int first = 4;
        int r = 20;
        for (int i = 1; i <= limit; i++) {
            sum += first;
            first += r;
            r += 32;
        }
        System.out.println(sum);
    }

}

Explanation: 说明:

Starting from 1 you can see 4 sums: 1开始,您可以看到4个总和:

  • 1 + 3 + 13 + 31 + 57 + ... 1 + 3 + 13 + 31 + 57 + ......
  • 1 + 5 + 17 + 37 + 65 + ... 1 + 5 + 17 + 37 + 65 + ......
  • 1 + 7 + 21 + 43 + 73 + ... 1 + 7 + 21 + 43 + 73 + ......
  • 1 + 9 + 25 + 49 + 81 + ... 1 + 9 + 25 + 49 + 81 + ......

1 is added 4 times, this is why the default value for sum is -3 . 1加上4次,这就是sum的默认值为-3

Let's gather those sums: 我们收集这些款项:

  • 4 + 24 + 76 + 160 + 276 + ... (this is why first is 4 and r is 20 = 24 - 4) 4 + 24 + 76 + 160 + 276 + ...(这就是为什么first4r20 = 24 - 4)

You can observe that r increases by 32 per step ( 24 - 4 = 32 + 76 - 24 = 32 + 32 + 160 - 76 = ... ) and the actual number ( first ) increases by r . 您可以观察到r每步增加32 (24 - 4 = 32 + 76 - 24 = 32 + 32 + 160 - 76 = ...),实际数( first )增加r

The first problem I saw was a NegativeArraySizeException when running your program with SIZE = 100. I guess this has something to do with how each recursive call is decreasing the size by 2. 我看到的第一个问题是在运行SIZE = 100的程序时出现NegativeArraySizeException。我想这与每个递归调用如何将大小减小2有关。

I believe that Steven's comment is right on the money. 我相信史蒂文的评论是正确的。 You are allocating the size of the array, them making a recursive call. 您正在分配数组的大小,它们进行递归调用。 This causes (SIZE - 1) number of arrays to be allocating, eating up all of your memory. 这会导致(SIZE - 1)数组的数量分配,占用你所有的内存。 Removing that one line should prevent any memory from being allocated until necessary. 删除该行应防止在必要时分配任何内存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM