【问题标题】:Stackoverflow when arrays get too big [closed]数组太大时的 Stackoverflow [关闭]
【发布时间】:2018-07-03 13:36:48
【问题描述】:

我正在尝试使用浮动的测试类来实现快速排序版本。当我尝试生成大小为 10⁸ 的数组时,在运行我的测试类时会出现堆栈溢出。

我尝试了 10⁷ 的数组大小,效果很好

在我的测试类中,我生成了两个完全相同的数组,一个使用我的算法排序,一个使用 javas Arrays.sort() 排序。

这是我的测试类的样子。

package Quicksort;

import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import static org.junit.Assert.*;

public class QuickSortTest {

private static float[] quickSort, javaSort;
private final static int SIZE = (int) 1e7;

@Before
public void init(){
    System.gc();
    quickSort = new float[SIZE];
    javaSort = new float[SIZE];
    for(int i = 0; i < SIZE; i++){
        int temp = (int) (Math.random() * 1000) + 1;
        quickSort[i] = temp;
    }

    javaSort = quickSort;
}

@Test
public void testQuickSort(){
    QuickSort.sort(quickSort);
    Arrays.sort(javaSort, 0, SIZE);
    assertArrayEquals(quickSort, javaSort, .0f);
}

}

快速排序实现:

private static void quickSort(float[] table, int first, int last){
        if(first < last){
            int pivotIndex = partition(table, first, last);
            quickSort(table, first, pivotIndex - 1);
            quickSort(table, pivotIndex + 1, last);
        }
    }

public static int partition(float[] table, int first, int last){
        sort3(table, first, last);
        swap(table, first, (first + last) / 2);
        float pivot = table[first];
        int up = first;
        int down = last;
        do{
            while((up < last) && table[up] <= pivot){
                up++;
            }
            while(table[down] > pivot){
                down--;
            }
            if(up < down){
                swap(table, up, down);
            }
        }while(up < down);
        swap(table, first, down);
        return down;
    }

【问题讨论】:

  • 你需要发布QuickSort的实现
  • 第一次递归调用时堆栈溢出。
  • 我喜欢您的测试断言:在测试准备中,您确保 javaSortquickSort 引用相同的数组 - 因此 assertArrayEquals(quickSort, javaSort, .0f); 将始终成功
  • 问题是您的输入数据不适合快速排序算法。您准备输入数据的方式 (int temp = (int) (Math.random() * 1000) + 1;) 意味着您的输入仅包含从 1 到 1000 的值,但这些值包含很多次(每个值约为 1e8/1000 = 100'000 次)。这是快速排序算法最糟糕的场景之一(见en.wikipedia.org/wiki/Quicksort#Repeated_elements

标签: java stack-overflow quicksort


【解决方案1】:

StackOverflowError 通常是由错误的递归调用引起的。你的QuickSort 类有一个递归函数,当你传入一个长度为 10^8 的数组时,它会不断调用自身超出堆栈大小。

解决此问题的一种方法是将您的实现切换为迭代方法而不是递归方法。

根据您的上次更新,partition() 方法似乎在超出 Java 堆空间限制的情况下递归调用自身。

在这个post 中,你可以找到一个迭代的partition() 实现。它稍微复杂一些,但能够处理数组的大小。

import java.util.Arrays;
import java.util.Random;

// Java program for implementation of QuickSort
class QuickSort
{
    public static void main(String[] args) {
        QuickSort sort=new QuickSort();
        int[] randomArray = createRandomArray((int) Math.pow(2, 20));

        sort.qSort(randomArray);
        //System.out.println(Arrays.toString(randomArray));
    }

    private void qSort(int[] arr) {
        this.qSort(arr, 0, arr.length-1);
    }

    /* This function takes last element as pivot,
       places the pivot element at its correct
       position in sorted array, and places all
       smaller (smaller than pivot) to left of
       pivot and all greater elements to right
       of pivot */
    int partition(int arr[], int low, int high)
    {
        int pivot = arr[high];
        int i = (low-1); // index of smaller element
        for (int j=low; j<=high-1; j++)
        {
            // If current element is smaller than or
            // equal to pivot
            if (arr[j] <= pivot)
            {
                i++;

                // swap arr[i] and arr[j]
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }

        // swap arr[i+1] and arr[high] (or pivot)
        int temp = arr[i+1];
        arr[i+1] = arr[high];
        arr[high] = temp;

        return i+1;
    }

    /* The main function that implements QuickSort()
      arr[] --> Array to be sorted,
      low  --> Starting index,
      high  --> Ending index */
    void qSort(int arr[], int low, int high)
    {
        if (low < high)
        {
            /* pi is partitioning index, arr[pi] is
              now at right place */
            int pi = partition(arr, low, high);

            // Recursively sort elements before
            // partition and after partition
            qSort(arr, low, pi-1);
            qSort(arr, pi+1, high);
        }
    }


    private static int[] createRandomArray(int size){
        Random randNumGenerator = new Random();
        int[] arr = new int[size];
        for (int i=0; i<arr.length; i++)
        {
            arr[i] = (randNumGenerator.nextInt(100)+1);
        }
        return arr;
    }
}

您似乎想牢记以下内容;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-17
    • 1970-01-01
    • 2016-08-20
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    • 2013-04-02
    相关资源
    最近更新 更多