【问题标题】:Stackoverflowerror in Quicksort implementation快速排序实现中的 Stackoverflow 错误
【发布时间】:2018-10-21 06:45:57
【问题描述】:
import java.util.Random;

public class Quicksort {

    private int partition(int arr[], int first, int last) {

    int pivot = arr[last]; //Using last element as pivot
    int i = (first-1);//index of smaller element

    for (int j = first; j < last; j++) {
        //if current element is smaller than or equal to pivot
        //then swap the elements
        if (arr[j] <= pivot) {
            i++;
            //swapping occurs here
            //make a temp variable to the first element
            //swap arr[j] and arr[i]
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
            //i++;
        }
    }
    int temp = arr[i+1];
    arr[i+1] = arr[last];
    arr[last] = temp;
    return i+1;
}

private void quickSort(int arr[], int first, int last) {

    if (first < last) {
        int pivindex = partition(arr, first, last);
        quickSort(arr, first, pivindex-1);
        quickSort(arr, pivindex+1, last);
    }
}

public void sort(int[] arr) {
    quickSort(arr, 0, arr.length - 1);
}

public static int[] getRandoms(int count) {
    return new Random().ints().limit(count).toArray();
}

public static void main(String[] args) {
    Quicksort fix = new Quicksort();

    int[] randoms = getRandoms(40000);
    double startTime = System.currentTimeMillis();
    fix.sort(randoms);    
    double endTime = System.currentTimeMillis();
    System.out.println("Performance Time on Random Data:" + (endTime - startTime));

    //Benchmarking quicksort on already sorted data
    startTime = System.currentTimeMillis();
    fix.sort(randoms);
    endTime = System.currentTimeMillis();
    System.out.println("Performance Time on Sorted Data:" + (endTime - startTime));

}
}

我不完全确定为什么会收到 Stackoverflow 错误。当我只排序一次时,代码运行良好,但是,如果我尝试对相同的数据进行两次排序,那就是我得到错误的时候。

我了解 Stackoverflow 错误的发生是因为使用递归存在问题。在这种情况下,我的错误来自

线程“主”java.lang.StackOverflowError 中的异常 在 quicksort.Quicksort.quickSort(Quicksort.java:36)

这是..

if (first < last) {
        int pivindex = partition(arr, first, last);
        quickSort(arr, first, pivindex-1);
        quickSort(arr, pivindex+1, last);
    }

【问题讨论】:

  • 也许检查一下给定的数组索引是否已排序?
  • 它实际上是对数据进行排序吗?您说“运行良好”,但您的意思是它可以正常退出吗?
  • @mackycheese21 当我说它运行良好时,我的意思是如果我使用一个较小的数组,我可以打印出来查看,它会打印出来排序。对 40,000 个随机整数进行排序也是如此,直到我尝试对已经排序的数组进行排序。

标签: java recursion stack-overflow quicksort


【解决方案1】:

@mackycheese21 当我说它运行良好时,我的意思是如果我使用一个较小的数组,我可以打印出来并查看它,它会打印出来排序。对 40,000 个随机整数进行排序也是如此,直到我尝试对已排序的数组进行排序。

所以我猜你只是想检查数组是否已排序。 因为这看起来效率不高,我唯一能想到的另一件事是,您的 partition 方法是,对于排序数组,给出第一个或最后一个索引 - 分区时给出一个空数组和完整数组。这可能会导致无限递归。

我建议您只需在 partition 中添加一个检查,以检查索引是转到第一个还是最后一个索引,然后如果确实发生这种情况,就在中间拆分。

【讨论】:

  • 如果有帮助请告诉我!
【解决方案2】:
private int partition(int arr[], int first, int last) {

int pivot = arr[last]; //Using last element as pivot
int i = (first-1);//index of smaller element

for (int j = first; j < last; j++) {
    //if current element is smaller than or equal to pivot
    //then swap the elements
    if (arr[j] <= pivot) {
        i++;
        //swapping occurs here
        //make a temp variable to the first element
        //swap arr[j] and arr[i]
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        //i++;
    }
}
int temp = arr[i+1];
arr[i+1] = arr[last];
arr[last] = temp;
return i+1;
}

我发现问题出在分区方法中的 for 循环中。谢谢所有回答并试图帮助我的人。

【讨论】:

  • 你需要改变什么?什么解决了它?
  • @mackycheese21 抱歉,没关系,看来我以为我已经修好了。只要我使用 17,000 或更少的数组(我手动测试了不同的大小),我的数据就会正常排序,但是当我使用 18,000 或更大的数组时,我会继续出现溢出错误。
  • 啊。所以它不是在0 创建一个分区并分成一个空数组和一个完整数组?
  • @mackycheese21 是的,情况似乎并非如此。因为我的数据实际上是排序的,直到我测试一个大于 17000 的数组大小。这让我更加困惑。
  • @mackycheese21 实际上,您可能是对的。我一直在做一些研究,Dan Sp 有点确认我目前处于快速排序的最坏情况。会继续做研究。
【解决方案3】:

QuickSort 的平均复杂度为 O(n log(n))。然而,最坏的情况是 O(n^2)。这也与递归调用的“深度”有关。

平均情况下,深度是 log(n),对于 40,000 个数字,它约为 15。因此,当每个递归调用自身时,每次将当前数组分成两半,深度大约为 15。

最坏的情况:您将枢轴设为当前片段中的最后一个元素。第二次运行快速排序时,数字已经排序。因此,无论如何,枢轴最终都会结束,并且您的数组会分成两部分。一个是数组元素 1 到 39999,另一个是元素 40000。恭喜,您已成功找到 Quicksorts 最坏的情况。所有调用的“左侧”深度为 40,000。

所以,当一个方法调用另一个方法时,信息会被压入堆栈。在第一次运行中,相对较少的东西被压入堆栈。在第二种情况下,40,000 个方法调用被压入堆栈,因此您的溢出。

【讨论】:

  • 请问谁投了反对票?这正是将 QuickSort 应用于已排序的列表并且选择枢轴作为端点之一时发生的情况!
  • 我不确定谁投了反对票,但我明白你在说什么。我知道最坏的情况,因为我还在学习过程中,所以我以前从来没有处理过修复它。所以我不确定如何处理它。我的数据被排序,但是如果我在同一个列表上应用快速排序并且它的大小为 17000 或更高,那就是我得到溢出错误的时候。我很困惑为什么会发生在 17000 的大小上。
猜你喜欢
  • 1970-01-01
  • 2013-08-09
  • 2016-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
相关资源
最近更新 更多