简体   繁体   中英

trouble-shooting my quicksort algorithm in java?

while trouble-shooting my method for quicksort algorithm, this problem popped up;

consider this simple example of printing an array elements individually:

public static void print1(int[] arr, int start, int end){
        for (int k = start; k<end;k++){
            System.out.println(arr[k]);
        }
    }
    public static void print2(int[] arr, int start, int end){
        for (int k=start; k<=end;k++){
            System.out.println(arr[k]);
        }
    }

In the main, if I call:

public static void main(String[] args) {
        int[] data2 = new int[]{10,11,9,7,5};
       print1(data2,0,data2.length);
       System.out.println("___________");
       print2(data2,0,data2.length-1);
    }

both prints the same content, which is well and good; (Note, I pass data2.length and data2.length-1 as arguments to my print1 and print2 methods and the for-loop in each method changes accordingly)

Now comes the problem with quicksort regime: consider this code:

public static void quickSort2(int[] arr, int i, int j){
        if (i<j){
            int part =partition(arr, i, j);
            quickSort2(arr, i, part-1);
            quickSort2(arr, part+1, j); 
        }
    }

public static int partition(int[] arr, int start, int end){
        int pivot = arr[start];
        int i = start;
        for (int j = start+1;j<=end;j++){ // ******
            if (arr[j]<pivot){
                    i++;
                    int temp=arr[i];
                    arr[i]=arr[j];
                    arr[j]=temp;
            }
        }
        arr[start]=arr[i];
        arr[i]=pivot;
        return i;
    }

In the main;

public static void main(String[] args) {
       //int[] data = new int[]{5,10,1,9,4,4,8,3,6,2,7,4};
        int[] data = new int[]{3,4,1,2};
        int[] data2 = new int[]{10,11,9,7,5};
       System.out.print("Unsorted array data ");
       display(data);
       System.out.print("\nUnsorted array data2 :");
       display(data2);
       quickSort2(data, 0, data.length-1);
       System.out.println("_____________");
       quickSort2(data2,0,data2.length-1);
       System.out.print("\nSorted array data: ");
       display(data);
       System.out.print("\nSorted array data2:");
       display(data2);
}

works fine and good; now If I change the call to quickSort(data, 0, data.length) and change the for-loop line (marked in the code with ******* ) to for (int j = start+1;j<end;j++) , I get entirely different result: ie: first two elements are not sorted, but rest rest of it is sorted. I get

Sorted array data: [2, 1, 3, 4]

Sorted array data2:[5, 9, 7, 10, 11]

I need some help

After a quick look, I think there are two separate bugs - I discovered one for each of your quickSort2() calls in 'main`. Each was triggered because of the nature of the array you were trying to sort.

Bug 1: at line 9 in your main, you call:

quickSort(data, 0, data.length);

So, this is when you try to quickSort() {3,4,1,2}. The error occurs on the first recursive call to quickSort2() , the exact call with its arguments being

quickSort2({2,1,3,4}, 0, 1);

which then calls partition() with the same parameters

partition({2,1,3,4}, 0, 1);

This is where the error occurs. Look at the terms of your for-loop :

 for (int j = start+1; j< end;j++)

j will immediately be set to 1. End already equals 1. 1 < 1 is false, so the loop never triggers. Solution: just get rid of the +1 when assigning j a value. Your loop will look like this:

for (int j = start; j< end;j++) 

The initial case where i == j is will never trigger the if-statement so I believe it should be fine.

Bug 2: at line 11 in main, you call:

quickSort2(data2,0,data2.length-1);

The eventual error occurs at the same place as it did in the first bug - in partition() during the first recursive call to quickSort2() , which ends up having these parameters:

partition({5,9,7,10,11}, 0, 2);

The if-statement in your for-loop is never triggered, because 5 is the pivot and 9 and 7 are both larger. Thus i returns as zero, and this half of the array is never sorted again. As for a quick solution to this, I can't say there is one I can readily think of. You'd have to alter the logic of your sort.

Some notes/pointers that may help you out.

Quicksort algorithms, in general, aren't typically called all the way down the array. There is usually a base case in which sorting switches over to a different algorithm. Example, you have only 5 objects left to sort on this call. That's not that many, so let's switch to something simpler, such as insertion sort. Even though insertion sort is generally less efficient on large collections, when you get down to only having 5 or fewer objects to rearrange, it's not such a big deal.

Quicksort implementations also typically don't call the very first object in the collection the pivot. This is a bad method in general, as what if your list was already sorted, or reverse sorted? The time complexity would be pretty mediocre ( O(N 2 )). Instead, there is a method called "Median-Of-Three", which not only just might solve the second bug you have, but give you a better time-complexity.

While calling the first partition in your quicksort function you will also have to change:

quickSort2(arr, i, part-1);

to

quickSort2(arr, i, part);

This is because you are not using the last index (end). Hence your quicksort will be incomplete since you are not placing the last element before the pivot even if it has a lower value than pivot.

quickSort(data, 0, data.length-1);
//...
quickSort2(data2,0,data2.length-1);

I see the two quickSort is not the same, maybe you have a another function named quickSort you forget?Or just wrong written?

had a look at the code added some prints and found out, that after your modification is in the second run your pivot element 0, what is obviously wrong. I added some numbers to be the unsorted array data this: 3 4 1 2 7 5 6

3 4 1 2 7 5 6

pivot: 2
2 1 3 4 7 5 6

pivot: 0
2 1 3 4 7 5 6

2 1 3 4 7 5 6

2 1 3 4 7 5 6

pivot: 3
2 1 3 4 7 5 6

2 1 3 4 7 5 6

pivot: 6
2 1 3 4 6 5 7

pivot: 4
2 1 3 4 6 5 7

2 1 3 4 6 5 7

2 1 3 4 6 5 7

Sorted array data: 2 1 3 4 6 5 7

package quicksort;

public class Quicksort {

public static void main(String[] args) {
        int[] data = new int[]{3,4,1,2,7,5,6};
       System.out.print("Unsorted array data:\n");
       display(data);
       quickSort2(data,0,data.length);
       System.out.print("\nSorted array data:\n");
       display(data);
}

public static void quickSort2(int[] arr, int i, int j){
    display(arr);
    if (i<j){
        int part =partition(arr, i, j);
        quickSort2(arr, i, part-1);
        quickSort2(arr, part+1, j); 
    }
}

public static int partition(int[] arr, int start, int end){
    int pivot = arr[start];
    //System.out.println(pivot);
    int i = start;
    int temp;
    for (int j = start;j<end;j++){ // ******
        if (arr[j]<pivot){
                i++;
                temp=arr[i];
                arr[i]=arr[j];
                arr[j]=temp;
        }
    }
    arr[start]=arr[i];
    arr[i]=pivot;
    System.out.println("pivot: "+i);
    return i;
}

public static void display(int[] data){
for(int i=0;i<data.length;i++){
    System.out.print(data[i]+" ");
}
System.out.println("\n");
}}

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