【问题标题】:Merge Sort create memory heap合并排序创建内存堆
【发布时间】:2018-10-15 16:55:04
【问题描述】:

我编写了这个合并排序,它允许用户通过仅传递两个参数(一个 ArrayList 和一个比较器)来调用它:

public static < T > void mergeSort(ArrayList < T > array, Comparator < T > c) {
    int high = array.size()-1;
    sort(array, c, 0, high, new ArrayList < T > (high/2));
  }  

  protected static < T > void sort(ArrayList < T > array, Comparator < T > c, int low, int high, ArrayList < T > tmp) {
    if (low < high) {
      int mid = low + (high - low) / 2;
      sort(array, c, low, mid, tmp);
      sort(array, c, mid + 1, high, tmp);
      merge(array, c, low, mid, high, tmp);
    }
  } 

  protected static < T > void merge(ArrayList < T > array, Comparator < T > c, int p, int mid, int q, ArrayList < T > tmp) {
    tmp.clear();
    int i = p;
    int j = mid + 1;
    int k = 0;
    for (; i <= mid && j <= q; k++) {
      if (c.compare(array.get(i), array.get(j)) < 0)
        tmp.add(k, array.get(i++));
      else
        tmp.add(k, array.get(j++));
    }
    if (i <= mid && j > q) {
      while (i <= mid)
        tmp.add(k++, array.get(i++));
    } else {
      while (j <= q)
        tmp.add(k++, array.get(j++));
    }
    for (k = 0; k < tmp.size()-p; k++)
      array.set(k + p, tmp.get(k));

  }
}

调用它后,我尝试打印它的内容(我应该订购):

Sorting.mergeSort(arrayA, new LongComparator());
System.out.println(Arrays.toString(arrayA.toArray()));

但是我收到了这个错误:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3332)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
    at java.lang.StringBuilder.append(StringBuilder.java:136)
    at java.util.Arrays.toString(Arrays.java:4574)

如何改进我的归并排序?临时 ArrayList 是错误的主要原因吗?因为当我尝试订购数百万个数据时会发生此错误。使用 2-3 个元素就可以了。 编辑:这是我的第一个算法版本,它没有我需要做的只有两个参数的支持方法

public static < T > void sort(ArrayList < T > array, Comparator < T > c, int low, int high) {
    if (low < high) {
      int mid = low + (high - low) / 2;
      sort(array, c, low, mid);
      sort(array, c, mid + 1, high);
      merge(array, c, low, mid, high);
    }
  } 

@SuppressWarnings("unchecked")
  public static <T> void merge(ArrayList<T> array, Comparator<T> c, int p, int mid, int q) {
    Object[] tmp = new Object[q-p+1]; 
    int i = p;
    int j = mid+1;
    int k = 0;
    while (i <= mid && j <= q) {
        if (c.compare(array.get(i), array.get(j))<0)
          tmp[k] = array.get(i++);
        else
          tmp[k] = array.get(j++);
        k++;
    }
    if (i <= mid && j > q) {
        while (i <= mid) 
          tmp[k++] = array.get(i++);
    } else {
        while (j <= q)
          tmp[k++] = array.get(j++);
    }
    for (k = 0; k < tmp.length; k++)
      array.set(k+p, (T)tmp[k]);
  }

【问题讨论】:

  • 这绝对是一些堆内存。我怀疑 JVM 堆内存足够大,可以容纳一份数据集,但不能容纳两份。您可以通过使用java -Xmx2048m ... 启动程序来增加堆大小(在此示例中,您为 VM 提供 2 GB 的堆内存)。
  • 另外请记住,每个递归算法最终都会被 StackOverflowExceptions 怀疑,因为 AoT 和热点编译器都没有部署尾调用优化。
  • 在我的第一个版本中,我将临时 ArrayList 声明为合并函数,即使在 2000 万个整数上它也能正常工作。问题是现在我需要将声明移动到排序方法中,我认为问题是由它引起的。
  • 对于这“一堆”数据,递归并不是最佳选择。
  • ..核心问题:你不能将超过2^31-"a few"elements 分配给一个数组(列表)。(stackoverflow.com/a/3039805/592355stackoverflow.com/a/44546701/592355

标签: java algorithm methods merge heap


【解决方案1】:

解决问题的两种方法:

增加可用内存:如 Turing85 所述,使用 VM 选项运行具有更多内存的 java,例如 -Xmx2048m 以分配 2GB。

减少使用的内存: 使用 Long 和 Double 等基本类型的 ArrayList 使用的内存是使用基本类型 long / double 的等效数组的 4 倍(在我的简单实验中)。

ArrayList<Long> instead of long[]

由于多种原因,还会使代码运行速度显着变慢(如果您打算对非基本类型使用合并排序,您可能会看到性能提高,但内存增益不会那么显着)

【讨论】:

    猜你喜欢
    • 2023-03-11
    • 2017-12-26
    • 2014-01-08
    • 1970-01-01
    • 2021-01-19
    • 2013-04-10
    • 2020-12-02
    • 2012-11-24
    • 2017-07-21
    相关资源
    最近更新 更多