Median of Medians algorithm error - java

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)

Related

Why is my Binary search stuck in an endless loop?

I just had to pop in here to hopefully get a quick answer to my little problem. I'm trying to create a binary search method but ran into some problems. I created it iteratively, which my IDE(Intellij) apparently didn't like. It had me stuck in a endless loop of... well, you know the rest. Any suggestions?
Here is my simple, yet beautiful little snippet of code:
static int searchIt(int[] arr, int target){
int left = 0;
int right = arr.length - 1;
while (left <= right){
int mid = (right + left) / 2;
if(arr[mid] == target) {
return mid;
} else if(target < arr[mid]){
right = mid-1;
} else{
left = mid -1;
}
}
return -1;
}
No errors, not in runtime or compile time, just endless nothingness...
left value should be mid + 1 since if the your middle your target value greater than your mid value then you need to search the element in second half of your array
static int searchIt(int[] arr, int target){
int left = 0;
int right = arr.length - 1;
while (left <= right){
int mid = (right + left) / 2;
if(arr[mid] == target) {
return mid;
} else if(target < arr[mid]){
right = mid - 1;
} else{
left = mid + 1;
}
}
return -1;
}

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.

quick sort list in 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!
}
}

Categories