简体   繁体   中英

Quicksort issue in Java

I am trying to implement quickSort using recursion and several methods to assist. When I run the program I get an out of bounds message that tells me I have veered off into index -1 of the Array. Can anyone offer advice about fixing my quickSort method? (this is where the problem lies). I know my other methods are correct.

Example {7,6,5,4,3,2,1}

should come out to be {1,2,3,4,5,6,7}

public static <T extends Comparable<? super T>> void quickSort(T[] a) {
        quickSort(a,0,a.length - 1);
    }

    public static <T extends Comparable<? super T>> void quickSort(T[] a,int start,int end) { 
        if(start<end) {
            int pivotIndex = partition(a, start, end);
            quickSort(a,start,pivotIndex-1); // sort left partition
            quickSort(a,pivotIndex+1,end); // sort right partition
        }

    }

    public static <T extends Comparable<? super T>> int partition(T[] a, int start, int end) {
        int mid =midpoint(start,end);
        sortFirstMiddleLast(a,start,mid,end);


        swap(a,mid,end-1);
        int pivotIndex = end -1 ;
        T pivotValue = a[pivotIndex];

        int indexFromLeft = start +1 ;
        int indexFromRight = end -2;
        boolean done = false;
        while (!done) {
            while (a[indexFromLeft].compareTo(pivotValue)<0) {
                indexFromLeft++;
                }
            while (a[indexFromRight].compareTo(pivotValue)>0) {
                indexFromRight--;
            }
            if (indexFromLeft < indexFromRight) {
                swap(a,indexFromLeft,indexFromRight);
                indexFromLeft++;
                indexFromRight--;
            }
            else {
                done=true;
            }

        }
            swap(a,pivotIndex,indexFromLeft);
            pivotIndex=indexFromLeft;

        return pivotIndex;
    }

    public static <T extends Comparable<? super T>> void sortFirstMiddleLast(T[] a, int start, int mid, int end) {
        if (a[start].compareTo(a[mid])>0) {
            swap(a,start,mid);
        }
        else if (a[mid].compareTo(a[end])>0) {
            swap(a,mid,end);
        }
        else if (a[start].compareTo(a[end])>0) {
            swap(a,start,end);
        }
        else if(a[start].compareTo(a[mid])>0) {
            swap (a,start,mid);
        }

        }

    private static int midpoint(int first, int last) {
            return first + (last - first) / 2;
        }

private static void swap(Object[] a, int first, int second) {
        Object temp = a[first];
        a[first] = a[second];
        a[second] = temp;
    }

The code is a variation of Hoare partition scheme. Assuming you don't want add a range check to the inner loops, then the pivot element needs to be within the range between left and right indexes. The if after the two inner loops should use left index <= right index (not <).

Another issue is that with a typical Hoare partition scheme, the pivot or elements = pivot can end up anywhere, and the index returned by partition may not be the pivot. The index just splits up the array into elements <= pivot and elements >= pivot (again elements == pivot or the pivot itself can end up anywhere). This means the calling code can't exclude the returned index from recursive calls. Also for the typical Hoare partition scheme, the last element can't be used for a pivot, since that can result in infinite recursion. Wiki article has an example of a pre-incrementing and pre-decrementing Hoare based quicksort.

https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme

Example C code for a post increment and decrement variation of Hoare partition scheme, with the partition logic merged into the quicksort function. For this particular variation of Hoare partition scheme, any element, including the last element, can be used for the pivot, but choosing first or last element for pivot results in worst case time complexity of O(n^2) for already sorted or reverse sorted data, while choosing the middle element as shown below results in best case behavior for already sorted or reverse sorted data.

void QuickSort(int a[], int lo, int hi)
{
int i, j;
int p, t;
    if(lo >= hi)
        return;
    p = a[lo + (hi-lo)/2];
    i = lo;
    j = hi;
    while (i <= j){
        while (a[i] < p)i++;
        while (a[j] > p)j--;
            if (i > j)
                break;
            t = a[i];
            a[i] = a[j];
            a[j] = t;
            i++;
            j--;
    }
    QuickSort(a, lo, j);
    QuickSort(a, i, hi);
}

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