当前位置: 首页 > 知识库问答 >
问题:

快速排序:更改枢轴元素会导致堆栈溢出

陆阳曜
2023-03-14

尝试使用Hoare分区方案实现快速排序,但我遇到了一个问题,即无论数组大小如何,更改pivot的索引都会导致溢出。代码

public void quickSort(int[] l, int min, int max){
    if (min < max){
        int p = partition(l, min, max);
        quickSort(l, min, p);
        quickSort(l, p+1, max);
    }
}
public int partition(int[] l, int min, int max){
    int pivot = l[min];
    int i = min - 1;
    int j = max +1;
    while(true){
        do{
            i++;
        }while(l[i] < pivot);
        do{
            j--;
        }while(l[j] > pivot);

        if (i >= j) {
                return j;
        }
        //Swap
        int temp = l[i];
        l[i] = l[j];
        l[j] = temp;
    }

}

这个实现选择低索引(这里名为min)作为轴心元素,这样做很好。但是,将pivot元素更改为任何其他索引都会导致StackOverflow错误,而与正在排序的数组的大小无关。(错误参考第3行,其中调用了partition())我最好在(min,max)范围内随机选择pivot元素。这是什么原因造成的?

编辑:使用的数组生成如下:

public static int[] generateRandomArray(int size, int lower, int upper){
    int[] random = new int[size];
    for (int i = 0; i < random.length; i++) {
        int randInt = ThreadLocalRandom.current().nextInt(lower, upper+1);
        random[i] = randInt;
    }
    return random;
}

在一个溢出案例中,我使用了以下方法:

genereateRandomArray(10, 0, 9);

对于一些具体的例子,运行上面的代码,但将pivot元素更改为l[max-1]或l[min 1],l[min 2]等,会导致StackOverflow。

我的问题的解决方案是,正如用户MBo指出的那样,将枢轴元素交换到数组的第一个索引,因为算法本身依赖于索引0上的枢轴。这是我忽略的。(int i=min-1;是正确的,但保持这种方式。)

共有2个答案

索嘉石
2023-03-14

使用pivot的中间值对我来说很有用。下面是一个完整的示例:

    public static void quickSort(int[] l, int min, int max){
        if (min < max){
            int p = partition(l, min, max);
            quickSort(l, min, p);
            quickSort(l, p+1, max);
        }
    }

    public static int partition(int[] l, int min, int max){
        int pivot = l[(min+max)/2];
        int i = min - 1;
        int j = max + 1;
        while(true){
            do{
                i++;
            }while(l[i] < pivot);
            do{
                j--;
            }while(l[j] > pivot);

            if (i >= j) {
                    return j;
            }
            int temp = l[i];
            l[i] = l[j];
            l[j] = temp;
        }
    }

    public static int[] generateRandomArray(int size, int lower, int upper){
        int[] random = new int[size];
        for (int i = 0; i < random.length; i++) {
            int randInt = ThreadLocalRandom.current().nextInt(lower, upper+1);
            random[i] = randInt;
        }
        return random;
    }

    public static void main(String[] args) {
        int[] A = generateRandomArray(10, 0, 9);
        long bgn, end;
        bgn = System.currentTimeMillis();
        quickSort(A, 0, A.length-1);
        end = System.currentTimeMillis();
        for(int i = 1; i < A.length; i++){
            if(A[i-1] > A[i]){
                System.out.println("failed");
                break;
            }
        }
        System.out.println("milliseconds " + (end-bgn));
    }
贺高飞
2023-03-14

我们可以看到,在第一步i变为等于min,枢轴元素与其自身的比较失败,增量不会发生更多:

int pivot = l[min];
    int i = min - 1;
...
 do{
            i++;
        }while(l[i] < pivot);

从比较中排除pivot元素(inti=min;),并在最后将其与分区1(似乎是l[j])交换

 类似资料:
  • 我有一个执行快速排序的应用程序。在我开始给它一些更大的数字(我第一次得到它是10000000)之前,它工作得很好。我知道是由递归引起的,但我不明白为什么我的应用程序会因此而崩溃。如有任何建议,将不胜感激。这是我的密码:

  • 我试图实现就地快速排序,最后一个元素作为我的支点。下面附上我的代码 出于某种原因,我的代码给了我一个IndexOutOfBounds异常,它不能准确地对数组排序。我不知道为什么会出现这个错误。 如果我理解正确,我们应该把最后一个元素作为我们的轴心。然后,我们将左指针向右迭代,直到找到一个大于枢轴的元素。之后,我们从右侧(继续向左移动)执行相同的操作,直到找到一个小于轴的元素。然后我们交换这些元素,

  • 问题内容: 这有效:http : //play.golang.org/p/-Kv3xAguDR。 这导致堆栈溢出:http : //play.golang.org/p/1-AsHFj51O。 我不明白为什么。在这种情况下,使用接口的正确方法是什么? 问题答案: 这个 将呼叫您的,依次呼叫,等等。如果您需要解组JSON然后对其进行处理,那么一种巧妙的技术是声明一个本地类型,将数据解组到其中,然后转换

  • 问题内容: 我目前正在用Java编写一种快速排序算法,以对整数的随机数组进行排序,然后使用System.nanoTime()对它们进行计时。这些数组的大小是10的幂,从10 ^ 3到10 ^ 7结束。此外,随机列表具有不同的属性。我正在对纯随机列表进行排序,具有一些相同值的列表(fewUnique),反向排序的列表,已排序的列表和几乎已排序的列表。 排序有效。它对数组进行递归快速排序,直到需要对数

  • 我正在使用一个正则表达式从任意长的输入字符串中提取键值对,并且遇到了这样的情况:对于具有重复模式的长字符串,它会导致堆栈溢出。 KV解析代码如下所示: 一些虚构的输出示例: 我显式地将generic放在上面,而不是在解析之前检查最大字符串长度的hacks(例如)。 我能想出的最粗俗的解决方法,一个真正的反模式,是 有趣的是,它在我试过的几次运行中都起作用了,但它不是一个值得推荐的有品位的东西。:-

  • 因为最坏情况下的快速排序复杂度为O(n^2) 在递增顺序的情况下,当pivot选择第一个或最后一个元素时,它给出了正确的最坏情况复杂度O(n^2),因为树的一个子元素总是空的 但是当枢轴选择中间时,我感到困惑?它将树分成两半,使其复杂性O(n.logn) 假设10 20 30 40 50 60 70枢轴=40 (10 20 30 ) 40 (50 60 70) 左侧枢轴20,右侧枢轴60 (10)