The Output: ATXZK (Not Sorted) Why?
There are no bugs in it. I can not figure it out.
Is there any problem with the method qs(items, left, right)
It works fine with input: d x a r p j i
class Quicksort{
static void qsort(char items[]) {
qs(items, 0, items.length - 1);
}
private static void qs(char items[], int left, int right)
{
int i, j;
char x, y;
i = left; j = right;
x = items[(left + right)/2];
do {
while((items[i] < x) && (i < right)) i++;
while((x < items[j]) && (j > left)) j--;
if(i <= j) {
y = items[i];
items[i] = items[j];
items[j] = y;
i++; j--;
}
} while(i <= j);
if(left < j) qs(items, left, j);
if(i > right) qs(items, i, right);
}
}
I think you reversed your greater/less than sign in your last line of code.
Should be:
Is i (which counts from left to right) less than right: If so, keep sorting.
Currently it is:
Is i (which counts from left to right) GREATER than right (IE, out of bounds). If so, keep quicksorting.
if(i < right) qs(items, i, right);
At least, this made your fail case work on my machine. :)
Related
I know that there are other question about this, but nobody has my implementation of quicksort so I need your help to fix this.
Here is my quicksort:
//u is first index (0) and v is last (numberOfPatients - 1)
public void quickSort(Patient arrayPatients[], int u, int v) {
int q;
if(u == v) return;
q = perno(arrayPatients, u, v);
if(u < q) quickSort(arrayPatients, u, q-1);
if(q < v) quickSort(arrayPatients, q+1, v);
}
public int perno(Patient arrayPatients[], int first, int last){
Patient temp = new Patient();
int i = first;
int j = last + 1;
long pivot = arrayPatients[first].priority;
while(i < j){
do i++;
while(arrayPatients[i].priority <= pivot && i<= last); //Line 1441
do j--;
while(arrayPatients[j].priority > pivot && j >= first);
if(i < j){
//Swap arrayPatients[i] and arrayPatients[j]
temp = arrayPatients[i];
arrayPatients[i] = arrayPatients[j];
arrayPatients[j] = temp;
}
}
//Swap arrayPatients[first] and arrayPatients[j]
temp = arrayPatients[first];
arrayPatients[first] = arrayPatients[j];
arrayPatients[j] = temp;
return j;
}
edit:
I have 4 patients, this is the error I get:
java.lang.ArrayIndexOutOfBoundsException: 4
at sorter.Sort.perno(Sort.java:1441)
at sorter.Sort.quickSort(Sort.java:1425)
at sorter.Sort.quickSort(Sort.java:1428)
at sorter.Sort.sorting(Sort.java:851)
at sorter.Home$27.run(Home.java:1314)
I've added a comment with the number of the incriminated line
Your problem is most likely due to checking array at index first, then checking if the index is within bounds at all.
Instead:
do i++;
while(arrayPatients[i].priority <= pivot && i<= last); //Line 1441
do j--;
while(arrayPatients[j].priority > pivot && j >= first);
Try:
do i++;
while(i<= last && arrayPatients[i].priority <= pivot); //Line 1441
do j--;
while(j >= first && arrayPatients[j].priority > pivot);
and see if that helps.
Here is what my quick sort looks like:
public int[] arrayToSort = {5, 1, 3, 2, 2, 9};
...
private void quickSort(int left, int right) {
int i = left;
int j = right;
int pivot = arrayToSort[(left + right - left) / 2];
while (i <= j) {
while (arrayToSort[i] < pivot) {
i++;
}
while(arrayToSort[j] > pivot) {
j--;
}
if(i <= j) {
swap(arrayToSort, i, j);
i++;
j--;
}
}
if(left < j) {
quickSort(left, j);
}
if(i <right) {
quickSort(i, right);
}
}
private void swap(int[] arrayToSort, int i, int j) {
int temp = arrayToSort[i];
arrayToSort[i] = arrayToSort[j];
arrayToSort[j] = temp;
}
I'm really not sure why I get a StackOverflowError in the first line of the quickSort(..) method. What is the problem? Not sure how I could use the debugger to help me here.
Thanks in advance
This line is almost certainly wrong.
(left + right - left) / 2
is the same as
right / 2
most likely this should be
left + (right - left) / 2
or possibly even
(left + right) >>> 1
as it is in the JDK.
Not sure how I could use the debugger to help me here.
In the debugger it would have been harder to see that the mid was being calculated incorrectly without putting it into a variable or in an expression.
I'm trying to practice quick sort list using java, I think this is correct but it shows "Exception in thread main..."
public class QuickSort {
public static void sort(List<Integer> list) {
sort(list, 0, list.size() - 1);
}
public static void sort(List<Integer> list, int from, int to) {
if (list.size() <= 1) {
return;
}
int pivot = from;
int left = from + 1;
int right = to;
while (left < right) {
while (list.get(pivot) >= list.get(left)) {
left++;
}
while (list.get(pivot) <= list.get(right)) {
right--;
}
if (left < right) {
Collections.swap(list, left, right);
}
}
Collections.swap(list, pivot, left - 1);
sort(list, from, pivot - 1);
sort(list, pivot + 1, to);
}
}
Your problem is here:
while (list.get(pivot) <= list.get(right)) {
right--;
}
As, In the worst case, say an already sorted list, your right-- will be negative.
Take a look the following code, this will give you idea:
public static void quicksort(List<Integer> list, int left, int right) {
int q;
if (right > left) {
q = partition(list, left, right);
// after ‘partition’
// list[left..q-1] ≤ list[q] ≤ list[q+1..right]
quicksort(list, left, q - 1);
quicksort(list, q + 1, right);
}
}
static int partition(List<Integer> list, int left, int right) {
int P = list.get(left);
int i = left;
int j = right + 1;
for (;;) { // infinite for-loop, break to exit
while (list.get(++i) < P)
if (i >= right)
break;
// Now, list[i]≥P
while (list.get(--j) > P)
if (j <= left)
break;
// Now, list[j]≤P
if (i >= j)
break; // break the for-loop
else
// swap(list[i],list[j]);
Collections.swap(list, i, j);
}
if (j == left)
return j;
// swap (list[left],list[j]);
Collections.swap(list, left, j);
return j;
}
See a demo run here.
Try with this:
public static void sort(List<Integer> list) {
sort(list, 0, list.size() - 1);
}
public static void sort(List<Integer> list, int from, int to) {
if (from < to) {
int pivot = from;
int left = from + 1;
int right = to;
int pivotValue = list.get(pivot);
while (left <= right) {
// left <= to -> limit protection
while (left <= to && pivotValue >= list.get(left)) {
left++;
}
// right > from -> limit protection
while (right > from && pivotValue < list.get(right)) {
right--;
}
if (left < right) {
Collections.swap(list, left, right);
}
}
Collections.swap(list, pivot, left - 1);
sort(list, from, right - 1); // <-- pivot was wrong!
sort(list, right + 1, to); // <-- pivot was wrong!
}
}
I'm implementing a select-kth algorithm using the Median of Medians pivot method. Specifically, I'm following the pseudocode listed here.. However, my code crashes (error discussed below), I see why it crashes, but I don't understand what I can do about it.
The Error
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 32017219
at Selection.partition(Selection.java:173)
The Reason
In the wiki link, the method select will return a value if left == right. However, when the mutual recursion is called from the return statement of pivot, that means it will return a value (and not an index) back to the parent and the parent will set that value as the pivotIndex.
The Code
public static int alg5(int[] a, int left, int right, int k) {
if (left == right) {
return a[left];
}
while (true) {
int pivotIndex = pivot(a, left, right);
pivotIndex = partition(a, left, right, pivotIndex);
if (k == pivotIndex) {
return a[k];
} else if (k < pivotIndex) {
right = pivotIndex - 1;
} else {
left = pivotIndex + 1;
}
}
}
public static int pivot(int[] a, int left, int right) {
for (int i = left; i <= right; i = i + 5) {
int subRight = i + 4;
if (subRight > right) {
subRight = right;
}
int median5 = partition5(a, i, subRight);
swap(a, median5, (int)(Math.floor(i / 5)));
}
return alg5(a, left, (int)(left + Math.ceil((right - left) / 5) - 1), ((right - left) / 10));
}
public static int partition5(int[] a, int left, int right) {
Arrays.sort(a);
return ((a.length - 1) / 2);
}
public static int partition(int[] a, int left, int right, int pivotIndex) {
int pivotValue = a[pivotIndex];
a = swap(a, pivotIndex, right);
int storeIndex = left;
for (int i = left; i <= right; i++) {
int aOfi = a[i];
if (a[i] < pivotValue) {
swap(a, storeIndex, i);
storeIndex++;
}
}
swap(a, right, storeIndex);
return storeIndex;
}
I completely understand why my code isn't working, I just don't understand how to fix it since it looks to be exactly what the algorithm specifies. Pointers are greatly appreciated!
There are quite a few mistakes:
The method pivot should not modify the array a. It should just find a pivot for the future partition. A dirty fix is to call pivot(a.clone(), left, right);. (You shouldn't do this, just to give you an idea.)
Math.ceil((right - left) / 5) is an integer division. You should cast them to floats: Math.ceil(((float)(right - left)) / 5f).
In partition5, you sort the whole array a! You should just do comparisons to find the index of the median between a[left] and a[right].
At some point you might have right < left, so the first line of alg5 you should write if (left >= right)
I have been reading through all of the QuickSort questions on SO, but I cannot resolve this specific problem. By referencing the other questions and comparing my faults to theirs I have gotten to a specific point, that I cannot find the answer to, even in Debug mode.
I was repeatedly getting out of bounds -1, so I added a conditional check for
if(pivot > 0)
and that stopped the overflow, but since I am using 0 as my partition, It partitions once and then terminates. The first partition is correct, but if I change that number to include 0, the I get infinite recursion again. If I completely take the line out, I get index out of bounds errors that I cannot seem to tackle.
Here's where I am so far:
public class QuickSort {
int[] array;
public static void main(String[] args) {
QuickSort qs = new QuickSort();
qs.array = new int[] {35, 82, 2, 24, 57, 17};
qs.quickSort(qs.array, 0, qs.array.length - 1);
for(int i = 0; i < qs.array.length; i++) {
System.out.println(qs.array[i]);
}
}
public void quickSort(int[] array, int left, int right) {
if(array.length == 1) {
return;
}
if(left < right) {
int pivot = partition(array, left, right);
quickSort(array, left, pivot - 1);
quickSort(array, pivot + 1, right);
}
}
public int partition(int[] array, int left, int right) {
if(array.length == 1) {
return right;
}
int pivot = array[0];
int pivotIndex = 0;
int leftPointer = left - 1;
int rightPointer = right + 1;
while(pivotIndex < right) {
if(leftPointer > rightPointer) {
break;
}
leftPointer++;
while(leftPointer < array.length - 1 && array[leftPointer] <= pivot) {
leftPointer++;
}
rightPointer--;
while(rightPointer > leftPointer && array[rightPointer] > pivot) {
rightPointer--;
}
if(leftPointer < rightPointer) {
int temp = array[leftPointer];
array[leftPointer] = array[rightPointer];
array[rightPointer] = temp;
} else {
int temp = array[rightPointer];
array[rightPointer] = array[pivotIndex];
array[pivotIndex] = temp;
}
}
return rightPointer;
}
EDIT: After a few more alterations, I can now get it to always return an array without overflow, but it still only partitions once.
I'm pretty sure I fixed it now. You were increasing the left and right pointers within the partition method before you wanted to (outside of the "checks"). Change your partition method as follows:
public static int partition(int[] array, int left, int right) {
if(array.length == 1)
return right;
int pivot = array[0];
int pivotIndex = 0;
int leftPointer = left; // Remove the +1
int rightPointer = right; // Remove the +1
while(pivotIndex < right) {
if(leftPointer > rightPointer) {
break;
}
//leftPointer++;
while((leftPointer < array.length - 1) && (array[leftPointer] <= pivot)) {
leftPointer++;
}
//rightPointer--;
while((rightPointer > leftPointer) && (array[rightPointer] > pivot)) {
rightPointer--;
}
if(leftPointer < rightPointer) {
int temp = array[leftPointer];
array[leftPointer] = array[rightPointer];
array[rightPointer] = temp;
}
else {
int temp = array[rightPointer];
array[rightPointer] = array[pivotIndex];
array[pivotIndex] = temp;
}
}
return rightPointer;
}
You're returning "0" from partition whenever the array length is not 1, and setting that to the pivot. The if(pivot >= 0) will always be hit in that case, or it will iterate once if you used if(pivot > 0), which I think is the problem. If that's right, then correcting your return from partition (to "left" ?) should fix the problem.
I think you should change
if(leftPointer > rightPointer) {
break;
}
to
if(leftPointer >= rightPointer) {
break;
}
inside the while loop.
Also, I think you should compare leftPointer with rightPointer after either is changed,
// move to #### to perform compare after possible change
// if(leftPointer > rightPointer) break;
//leftPointer++;
while(leftPointer < array.length - 1 && array[leftPointer] <= pivot) leftPointer++;
//rightPointer--;
while(rightPointer > leftPointer && array[rightPointer] > pivot) rightPointer--;
//####
if(leftPointer > rightPointer) break;