You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

快速排序实现中出现StackOverflowError的原因排查求助

嘿,我来帮你搞定这个栈溢出的问题!

问题根源

你遇到的StackOverflowError完全是因为快速排序在最坏场景下的递归深度爆炸。

你的实现里固定选数组的最后一个元素当基准值(pivot),当数组已经完全有序(不管升序还是降序)时,每次partition操作都会把基准值放到数组的最右端(因为所有元素都≤它)。这就导致每次递归调用时,其中一个子数组的长度只比原数组少1,另一个子数组直接是空的。

举个例子,你测试用的是40000长度的数组,排序后再跑一次,递归深度会直接拉到40000层左右,但Java虚拟机默认的调用栈深度也就1000-2000层,根本扛不住,直接就栈溢出了。

解决方案

我们只要优化基准值的选择,就能避免这种极端最坏情况,给你两个常用的靠谱方案:

1. 随机选基准值

在分区前,随机挑一个元素和最后一个元素交换,再用原来的逻辑处理。这样哪怕数组有序,基准值也是随机的,不会让递归深度一路飙升。

修改后的partition代码:

private int partition(int arr[], int first, int last) {
    // 随机选一个位置,和最后一位交换
    Random rand = new Random();
    int randomPivotPos = first + rand.nextInt(last - first + 1);
    int temp = arr[randomPivotPos];
    arr[randomPivotPos] = arr[last];
    arr[last] = temp;
    
    // 下面是你原来的分区逻辑,不用改
    int pivot = arr[last]; 
    int i = (first-1);
    for (int j = first; j < last; j++) {
        if (arr[j] <= pivot) {
            i++;
            temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    temp = arr[i+1];
    arr[i+1] = arr[last];
    arr[last] = temp;
    return i+1;
}

2. 三数取中法选基准值

从数组的开头、中间、结尾三个位置里,挑大小居中的那个元素当基准值,这种方式对有序数组的优化效果特别好:

private int partition(int arr[], int first, int last) {
    // 找首、中、尾三个位置里的中间值
    int mid = first + (last - first) / 2;
    int pivotPos = mid;
    
    // 判断哪个位置的元素是中间值
    if ((arr[first] > arr[mid]) != (arr[first] > arr[last])) {
        pivotPos = first;
    } else if ((arr[mid] > arr[first]) != (arr[mid] > arr[last])) {
        pivotPos = mid;
    } else {
        pivotPos = last;
    }
    
    // 把基准值换到最后一位,复用原来的分区逻辑
    int temp = arr[pivotPos];
    arr[pivotPos] = arr[last];
    arr[last] = temp;
    
    // 原分区逻辑不变
    int pivot = arr[last]; 
    int i = (first-1);
    for (int j = first; j < last; j++) {
        if (arr[j] <= pivot) {
            i++;
            temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    temp = arr[i+1];
    arr[i+1] = arr[last];
    arr[last] = temp;
    return i+1;
}

额外优化:减少递归深度

除了基准值优化,还可以改一下递归逻辑,先处理较短的子数组,再用循环代替较长子数组的递归,这样能把递归深度压到O(log n):

private void quickSort(int arr[], int first, int last) {
    while (first < last) {
        int pivindex = partition(arr, first, last);
        // 先递归处理较短的子数组,避免深度爆炸
        if (pivindex - first < last - pivindex) {
            quickSort(arr, first, pivindex-1);
            first = pivindex + 1;
        } else {
            quickSort(arr, pivindex+1, last);
            last = pivindex - 1;
        }
    }
}

测试效果

改完之后再跑你的代码,不管是随机数组还是已排序数组,都不会再出现栈溢出了,而且排序速度也会快很多。

内容的提问来源于stack exchange,提问作者Mellow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:10:31