简体   繁体   English

Quicksort实施中的StackoverflowError

[英]Stackoverflowerror in Quicksort implementation

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));

}
}

I am not entirely sure why I'm getting a Stackoverflowerror. 我不完全确定为什么会收到StackoverflowError。 The code runs fine when I only sort once, however, if I try to sort the same data twice, that's when I get the error. 当我只排序一次时,代码运行良好,但是,如果我尝试对同一数据进行两次排序,那就是出现错误。

I understand Stackoverflowerror happens because there is a problem with the use of recursion. 我了解发生Stackoverflowerror是因为使用递归存在问题。 In this case, my error is coming from 在这种情况下,我的错误来自

Exception in thread "main" java.lang.StackOverflowError at quicksort.Quicksort.quickSort(Quicksort.java:36) quicksort.Quicksort.quickSort(Quicksort.java:36)处的线程“ main”中的异常java.lang.StackOverflowError

which is.. 是..

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

@mackycheese21 When I say it runs fine, I mean if I use a smaller array that I can print out and see, it will print it out sorted. @ mackycheese21当我说它运行良好时,我的意思是,如果我使用可以打印并看到的较小数组,它将按排序将其打印出来。 Same thing with sorting 40,000 random integers, until I try to sort the already sorted array. 排序40,000个随机整数也是如此,直到我尝试对已经排序的数组进行排序。

So I guess you just want to check if the array is sorted. 所以我想您只是想检查数组是否已排序。 Because this does not seem very efficient, the only other thing I can think of is that your partition method is, for sorted arrays, giving the first or last index - something that when partitioned, gives an empty array and the full array. 因为这看起来效率不高,所以我能想到的唯一另一件事是,您的partition方法是对有序数组给出第一个或最后一个索引-进行分区时给出一个空数组和整个数组。 This probably leads to infinite recursion. 这可能导致无限递归。

I would recommend you just add a check in partition to check whether the index is going to the first or last indeces and then if that does happen, just split in the middle. 我建议您只添加一个检入partition以检查索引是指向第一个还是最后一个索引,然后如果确实发生了,就在中间拆分。

QuickSort is on average O (n log(n)) complexity. QuickSort的平均复杂度为O (n log(n))。 However, its worst case is O (n^2). 但是,最坏的情况是O (n ^ 2)。 This also relates to the 'depth' of the recursive calls. 这也与递归调用的“深度”有关。

Average case the depth is log(n) which for 40,000 numbers is about 15. So when each recursion calls itself, each time splitting the current array piece in half, the depth gets to about 15. 平均情况下,深度为log(n),对于40,000个数字而言,深度约为15。因此,当每次递归调用自身时,每次将当前数组分割成两半时,深度都会达到15。

Worst case: You make the pivot the last element in the current piece. 最坏的情况:将枢轴作为当前片段的最后一个元素。 The second time you run quicksort, the numbers are already sorted. 第二次运行quicksort时,数字已经排序。 So the pivot ends up at the end anyway and your array gets split into 2 pieces. 因此,无论如何枢轴最终都将结束,并且您的阵列被分成2个部分。 One is array elements 1 through 39999 and the other is just element 40000. Congratulations, you have successfully found Quicksorts worst case. 一个是数组元素1到39999,另一个是元素40000。恭喜,您已经成功找到Quicksorts最坏的情况。 The depth of the 'left' side of all the calls will be 40,000. 所有通话的“左侧”深度为40,000。

So, when a method calls another method, information is pushed on the stack. 因此,当一个方法调用另一个方法时,信息被压入堆栈。 In the first run, relatively little gets pushed on the stack. 在第一轮中,很少有人被推入堆栈。 In the second case, 40,000 method calls are pushed on the stack, hence your overflow. 在第二种情况下,将40,000个方法调用压入堆栈,从而导致溢出。

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;
}

I figured out the problem was in my for-loop in the partition method. 我发现问题出在分区方法的for循环中。 Thanks, everyone who answered and tried to assist me. 谢谢,所有回答并尝试帮助我的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM