Qucksort获取100000个元素的StackOverflowError,但是mergesort不在Java

时间:2017-12-13 15:08:19

标签: java algorithm sorting quicksort mergesort

根据this SO帖子:

  

堆栈溢出的常见原因是错误的递归调用。

那么为什么它会运行10000个元素但是得到100000个元素的StackOverflowError?

快速排序

public static void quicksort(int[] data, int low, int high) {
    if (low < high) {
        int p = partition(data, low, high);
        quicksort(data, low, p);
        quicksort(data, p + 1, high);
    }
}
public static int partition(int[] data, int low, int high) {
    int pivot = data[low];
    int i = low - 1;
    int j = high + 1;
    while (true) {
        do {
            i++;
        } while (data[i] < pivot);
        do {
            j--;
        } while (data[j] > pivot);
        if (i >= j)
            return j;
        int temp = data[i];
        data[i] = data[j];
        data[j] = temp;
    }
}

归并

public static void mergesort(int[] data, int left, int right) {
    if (left < right){
        int middle = (left + right) / 2;
        mergesort(data, left, middle);
        mergesort(data, middle+1, right);
        merge(data, left, middle, right);
    }
}
private static void merge(int[] data, int left, int middle, int right) {
    int n1 = middle - left + 1;
    int n2 = right - middle;
    int[] dataLeft = new int[n1];
    int[] dataRight = new int[n2];
    for (int i = 0; i < n1; i++)
        dataLeft[i] = data[left+i];
    for (int i = 0; i < n2; i++) 
        dataRight[i] = data[middle+1+i];
    int i = 0, j = 0, k = left;
    while (i < n1 && j < n2) {
        if (dataLeft[i] <= dataRight[j]) {
            data[k] = dataLeft[i];
            i++;
        }
        else {
            data[k] = dataRight[j];
            j++;
        }
        k++;
    }
    while (i < n1) {
        data[k] = dataLeft[i];
        i++;
        k++;
    }
    while (j < n2) {
        data[k] = dataRight[j];
        j++;
        k++;
    }
}

对于mergesort,它运行得很好。

是什么原因?有人可以解释一下吗?

1 个答案:

答案 0 :(得分:2)

对于具有pivot int pivot = data[low];和已排序(或大部分)数组的所选分区方案,可以预期此行为,在这种情况下,堆栈深度可能会达到N=length of array

您必须了解更明智的支点选择 - median of threerandom pivot index。这些方法减少了特殊数据集的不良行为概率(但不能完全摆脱它)

第二步 - 优化递归方案:

  

为了确保最多使用O(log n)空间,首先递归到   分区较小的一侧,然后使用尾部调用递归   另一个。   因此,只需比较(p-low)high-p,然后选择这些调用的正确顺序:

    quicksort(data, low, p);
    quicksort(data, p + 1, high);

这些问题以及针对它们的更多解决方案很快在Wiki page详细解释 - 在任何算法书/课程中

请注意,mergesort始终提供最大堆栈深度log(N)