程序效率和java.lang.OutOfMemoryError:Java堆空间

时间:2013-03-09 22:28:11

标签: java memory heap space out

问题是要删除每个第二个元素,直到最后一个元素保留。 (假设元素放在圆圈中)

我的程序适用于n的小值,但是当我使用较大的值时,它会给我一条java.lang.OutOfMemoryError: Java heap space消息。

有些人可以帮助我解决我需要做些什么来提高我的代码效率并解决这个错误。

谢谢!

import java.util.*;

public class ArrayLists {
    public static void main(String[] args) {
        ArrayList myList = new ArrayList();
        int n = 23987443;
        for (int i = 1; i <= n; i = i + 2) {
            myList.add("" + i);
        }

        Object x = myList.get(myList.size() - 1);
        Object y = myList.get(myList.size() - 1);
        while (myList.size() != 1) {
            if (x == y) {
                for (int i = 0; i <= myList.size() - 1; i++) {
                    myList.remove(i);
                }
            } 
            else {
                x = y;
                for (int i = 1; i <= myList.size() - 1; i++) {
                    myList.remove(i);
                }
            }
            y = myList.get(myList.size() - 1);
        }
        System.out.println("Winner:" + myList);
    }
}

3 个答案:

答案 0 :(得分:2)

您正在构建庞大的字符串列表。因此,您需要足够的内存来容纳所有列表。您可以通过使用适当的大小初始化列表来减少消耗,避免使用临时副本来放大列表:

int n = 23987443;
List<String> myList = new ArrayList<String>(23987443);

您也可以使用List<Integer>,因为这是列表实际包含的内容。

但是一大堆字符串需要大量内存。使用

放大堆大小
java -Xmx1024m ...
例如

(1024 MB的堆)

答案 1 :(得分:1)

这使用更少的内存,但引用速度更快,因为它是O(N * log N)而不是O(N^2 * log N)

public static void main(String[] args) {
    // for (int n = 1; n < 400; n++) {
    int n = 23987443;
    System.out.print(n + ": ");
    result(n);
    // }
}

private static void result(int n) {
    List<Integer> myList = new ArrayList<>(), myList2 = new ArrayList<>();
    for (int i = 1; i <= n; i = i + 2) {
        myList.add(i);
    }

    Integer x = myList.get(myList.size() - 1);
    Integer y = myList.get(myList.size() - 1);
    while (myList.size() != 1) {
        if (x == y) {
            for (int i = 1; i < myList.size(); i += 2) {
                myList2.add(myList.get(i));
            }
        } else {
            x = y;
            for (int i = 0; i <= myList.size() - 1; i += 2) {
                myList2.add(myList.get(i));
            }
        }
        List<Integer> tmp = myList2;
        myList2 = myList;
        myList = tmp;
        myList2.clear();

        y = myList.get(myList.size() - 1);
       // System.out.println("\t" + myList);
    }
    System.out.println("Winner:" + myList.get(0));
}

注意:如果您使用TIntArrayList而不是ArrayList<Integer>,它将使用大约1/5的内存。

答案 2 :(得分:0)

您的问题的答案可以使用封闭的表格计算,如果您在列表中写下元素的数量,如下所示:

n = 2 ^ m + l

其中m是2的最大幂,使得2 ^ m <= n

然后获胜者是w = 2 * l + 1。

所以这是一个更有效的计划:

public class ArrayLists {
  public static void main(String[] args) {
    int n = 23987443;
    int pow = Integer.highestOneBit(n);
    int l = n - pow;
    System.out.println("Winner:[" +((2*l)+1)+"]" );
  }
}

n值的答案:

Winner:[14420455]

说实话,我自己没有想出解决方案,但记得在“混凝土数学”一书中读到约瑟夫斯问题(谷歌将找到PDF,请查看第1.3节)