简体   繁体   中英

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. 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. In this case, my error is coming from

Exception in thread "main" java.lang.StackOverflowError at quicksort.Quicksort.quickSort(Quicksort.java:36)

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. Same thing with sorting 40,000 random integers, until I try to sort the already sorted array.

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. 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.

QuickSort is on average O (n log(n)) complexity. However, its worst case is 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.

Worst case: You make the pivot the last element in the current piece. The second time you run quicksort, the numbers are already sorted. So the pivot ends up at the end anyway and your array gets split into 2 pieces. One is array elements 1 through 39999 and the other is just element 40000. Congratulations, you have successfully found Quicksorts worst case. The depth of the 'left' side of all the calls will be 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.

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. Thanks, everyone who answered and tried to assist me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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