quick sort list in java - java

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

Related

QUICKSORT Not giving sorted array

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

Median-of-3 quick sort in java

I have a task in the university where I need to sort student by their groupnumbers using Median-of-3 quick sort. But my sorting methods are not working properly - only some of the elements are sorted. But a few elements do not change their positions.
I have created a Student class with necessary data, Sortings class with Student type array. And I have 4 static methods for this type of sorting in main class, where I create an instance of Sortings and call my static methods for sorting.
public static void manual_Sort(Student[]st, int right, int left)
{
int size = right - left + 1;
if(size <= 1)
return;
if(size == 2)
{
if(st[left].Group_number > st[right].Group_number)
swap(st,right,left);
return;
}
else
{
if(st[left].Group_number > st[right-1].Group_number)
swap(st,left, right-1);
if(st[left].Group_number > st[right].Group_number)
swap(st,left, right);
if(st[right-1].Group_number > st[right].Group_number )
swap(st,right-1, right);
}
}
public static int partitionIt(Student[]st, int left, int right,double pivot)
{
int leftPtr = left;
int rightPtr = right - 1;
while(true)
{
while(st[++leftPtr].Group_number < pivot)
;
while(st[--rightPtr].Group_number > pivot)
;
if(leftPtr >= rightPtr)
break;
else
swap(st,leftPtr, rightPtr);
}
swap(st,leftPtr, right-1);
return leftPtr;
}
public static int median_OfThree(Student[]st, int left, int right)
{
int center = (left + right)/2;
if(st[left].Group_number > st[center].Group_number )
swap(st,left, center);
if(st[left].Group_number > st[right].Group_number )
swap(st,left, right);
if(st[center].Group_number > st[right].Group_number )
swap(st,center, right);
swap(st,center, right-1);
return st[right-1].Group_number;
}
public static void quick_Sort(Student[] st)
{
rec_quickSort(st, 0, st.length-1);
}
public static void rec_quickSort(Student[]st, int left, int right)
{
int size_ = right - left + 1;
if(size_ <= 3)
manual_Sort(st, left, right);
else
{
double median = median_OfThree(st, left, right);
int partition = partitionIt(st, left, right, median);
rec_quickSort(st, left, partition - 1);
rec_quickSort(st, partition + 1, right);
}
}

Getting StackOverflowError when trying to use Quick Sort method

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.

Median of Medians algorithm error

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)

QuickSort (Java) implementation either overflows or stops short

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;

Categories