This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 3 years ago.
I'm learning datastructures and algorithms. So I have tried implementing the quick sort alogorithm.
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = new int[] { 10, 16, 8, 12, 15, 6, 3, 9, 5 };
quickSort(0, arr.length - 1, arr);
}
public static void quickSort(int start, int end, int[] arr) {
if (start < end) {
int partitionIndex = partition(start, end, arr);
quickSort(start, partitionIndex - 1, arr);
quickSort(partitionIndex+1, end, arr); // When passing partitionIndex+1 in the swap method it throws index out of bound exception
System.out.println(Arrays.toString(arr));
}
}
public static int partition(int start, int end, int[] arr) {
int pivot = arr[end];
int pIndex = start;
for (int i = 0; i < end - 1; i++) {
if (arr[i] <= pivot) {
swap(i, pIndex, arr);
pIndex++;
}
}
swap(pIndex, end, arr);
return pIndex;
}
private static void swap(int i, int index, int[] arr) {
int temp = arr[i];
arr[i] = arr[index]; // index out of bound exception is thrown
arr[index] = temp;
}
When doing the recursive call quickSort(partitionIndex+1, end, arr); and in the swap method it is throwing index out of bound exception. Because there is no such index to retrieve/store the value.
Can any one please help me to resolve this issue?
I assume you tried to implement the Lomuto partition scheme from Wikipedia. If that's the case you have 2 errors in your code, both in the for loop of the partition method:
start index:
You algorithm starts every time at 0. That is causing the IndexOutOfBoundsException, because it swaps pIndex which is array.length at the end. If you fix this, the exception will be gone, but your sorted result will be [3, 5, 8, 10, 12, 15, 6, 16, 9], which is obviously not perfectly sorted.
end condition:
The error here is, that the last iteration is missing every time, because your end condition is i < end - 1 change that to i < end or i <= end - 1 and you should get a perfect result:
[3, 5, 6, 8, 9, 10, 12, 15, 16]
For completion here is the fixed partition method and your quickSort method:
public static void quickSort(int start, int end, int[] arr) {
if (start < end) {
int partitionIndex = partition(start, end, arr);
quickSort(start, partitionIndex - 1, arr);
quickSort(partitionIndex + 1, end, arr);
}
}
public static int partition(int start, int end, int[] arr) {
int pivot = arr[end];
int pIndex = start;
for (int i = start; i < end; i++) {
if (arr[i] < pivot) {
swap(pIndex, i, arr);
pIndex++;
}
}
swap(pIndex, end, arr);
return pIndex;
}
Related
This current quicksort implementation will sort an array to be in ascending order. How do I change this code so that it will sort an array to be in descending order? I need some help reversing the logic. Advice would be much appreciated.
public void quickSort(int[] array) {
// An array of size 1 is already sorted
if (array.length < 2)
return;
// Find the largest element and put it at the end of the array
int max = 0;
for (int i = 1; i < array.length; i++) {
if (array[i] > array[max]) {
max = i;
}
}
swap(array, array.length-1, max);
// Call the main quicksort method
quicksort(array, 0, array.length-1);
}
public void quicksort(int[] array, int first, int last) {
int lower = first + 1, upper = last;
// Use the middle array element as the bound (pivot) and
// move it out of the way into the first array element
swap(array, first, (first + last)/2);
int bound = array[first];
// Partition the array
while (lower <= upper) {
while (array[lower] < bound) {
lower++;
}
while (array[upper] > bound) {
upper--;
}
if (lower < upper) {
swap(array, lower++, upper--);
}
else {
lower++;
}
}
// Move the pivot into its proper position in the array
swap(array, upper, first);
// Recursively sort the lower and upper subarrays
if (first < upper-1) {
quicksort(array, first, upper-1);
}
if ((upper+1) < last) {
quicksort(array, upper+1, last);
}
}
So the basic concept would be to modify...
while (array[lower] < bound) {
lower++;
}
while (array[upper] > bound) {
upper--;
}
to match your requirements, but it's not particularly reusable. Instead, we want to delegate the comparison so that we can use the same code, but which can allow for different algorithms to be used, for example...
public class QuickSort {
public static interface Matcher {
public int compare(int lhs, int rhs);
}
public static void sort(int[] array, Matcher matcher) {
// An array of size 1 is already sorted
if (array.length < 2) {
return;
}
// Find the largest element and put it at the end of the array
int max = 0;
for (int i = 1; i < array.length; i++) {
if (matcher.compare(array[i], array[max]) > 0) {
max = 1;
}
}
swap(array, array.length - 1, max);
// Call the main quicksort method
sort(array, 0, array.length - 1, matcher);
}
protected static void sort(int[] array, int first, int last, Matcher matcher) {
int lower = first + 1, upper = last;
// Use the middle array element as the bound (pivot) and
// move it out of the way into the first array element
swap(array, first, (first + last) / 2);
int bound = array[first];
// Partition the array
while (lower <= upper) {
while (matcher.compare(array[lower], bound) < 0) {
lower++;
}
while (matcher.compare(array[upper], bound) > 0) {
upper--;
}
if (lower < upper) {
swap(array, lower++, upper--);
} else {
lower++;
}
}
// Move the pivot into its proper position in the array
swap(array, upper, first);
// Recursively sort the lower and upper subarrays
if (first < upper - 1) {
sort(array, first, upper - 1, matcher);
}
if ((upper + 1) < last) {
sort(array, upper + 1, last, matcher);
}
}
protected static void swap(int[] values, int first, int second) {
int temp = values[first];
values[first] = values[second];
values[second] = temp;
}
}
Which can then be used something like...
int[] values = new int[]{1, 0, 2, 9, 3, 8, 4, 7, 5, 6};
QuickSort.sort(values, new QuickSort.Matcher() {
#Override
public int compare(int lhs, int rhs) {
return Integer.compare(lhs, rhs);
}
});
System.out.println(Arrays.toString(values));
QuickSort.sort(values, new QuickSort.Matcher() {
#Override
public int compare(int lhs, int rhs) {
return Integer.compare(rhs, lhs);
}
});
System.out.println(Arrays.toString(values));
which will output...
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
I have been looking around but my confusion remains. I changed some things which people suggested around here but that only made the code worse.
I am using this list as a test int [] testing = {5, 2, 9, 6, 1, 7, 8, 10, 4, 12, 3, 13, 11};
and I am getting < 1 2 3 5 4 6 7 8 10 9 11 12 13 > as a result. (I made the errors bold)
My main quicksort method.
public static void quickieSorty(int[] array, int start, int end) {
int pivot;
pivot = originalPivot(array, start, end);
if (start < end)
{
pivot = originalPivot(array, start, end);
quickieSorty(array, start, pivot - 1);
quickieSorty(array, pivot + 1, end);
}
}
Partition (Here is were I changed some things inside the for loop, but that just made the list even less sorted).
private static int originalPivot (int[] array, int start, int end) {
int pivotValue;
int endOfList;
int mid;
mid = (start + end) / 2;
swap(array, start, mid);
pivotValue = array[start];
endOfList = start;
for (int i = start + 1; i <= end; i++)
{
if (array[i] < pivotValue)
{
endOfList++;
swap(array, endOfList, i);
}
}
swap(array, start, endOfList);
return endOfList;
}
Swap is the generic swap code
private static void swap (int[] array, int a, int b) {
int temp;
temp = array[a];
array[a] = array[b];
array[b] = temp;
}
I used my textbook and called a helper, but they told me they do not know for sure.
Any help is welcomed, thanks in advance for your time, and help!
Please see the below java source code for binary search implementation
public class Main {
public static void main(String[] args) {
int[] x = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
int y = binarySearch(x, 11);
System.out.println(y);
}
public static int binarySearch(int[] arr, int value) {
int searchedIndex = -1;
int first = 0;
int last = arr.length - 1;
int mid;
while (first <= last) {
mid = (first + last) / 2;
if (arr[mid] == value) {
searchedIndex = mid;
break;
} else {
if (value < arr[mid]) {
last = mid - 1;
} else {
first = mid + 1;
}
}
}
return searchedIndex;
}
}
int last = arr.length - 1 is -1 compulsory or not. I feel that code works fine either last = arr.length - 1. If its compulsory please explain why.
Arrays already have a method binarySearch you can just use :
int[] x = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
int r = Arrays.binarySearch(x, 11);
The -1 is needed for one very specific case: when you search for a value that is larger than the largest value in the array. For example, calling your function with
int y = binarySearch(x, 50);
will throw an ArrayOutOfBounds exception. That's because mid will eventually be equal to last, and without the -1, last is past the end of the array.
I have been having trouble with my mergesort() implementation since im returning an array i get stackoverflow error in mergesotrt(). my merge() works fine this is a small clippet my entire program has an ArraytoString() which work fine and prints to console im adding in alsp im not allowed to change the implementation type like the basic format has to remain
{37, 27, 43, 3, 9, 81, 10}
public static int[] merge(int[] arr1, int start, int mid, int end, int[] temp) {
int beginHalf1 = start;
int endHalf1 = mid;
int beginHalf2 = mid+1;
int endHalf2 = end;
//if odd its mid half of
int index = 0;
//until arraysect runs out check which is smaller and send to temp
while (beginHalf1 <= endHalf1 && beginHalf2 <= endHalf2){
if(arr1[beginHalf1] <= arr1[beginHalf2]){
temp[index] = arr1[beginHalf1];
beginHalf1++;
}else {//>=
temp[index] = arr1[beginHalf2];
beginHalf2++;
}
index++;
}//pass leftover items to array
if(beginHalf1>endHalf1){//right half not done
while (beginHalf2<=endHalf2){
temp[index] = arr1[beginHalf2];
beginHalf2++;
index++;
}
}else if(beginHalf2>endHalf2){ //left half not done
while (beginHalf1<=endHalf1){
temp[index] = arr1[beginHalf1];
beginHalf1++;
index++;
}
}
return temp;
}
public static int[] mergeSort(int[] arr, int start, int end, int[] temp) {
//arr unsorted returns sorted copy of that array
//idk why it doesnt run
if (start < end) {
int mid = ((start + end) / 2)-1;//offset for mid for odd size
mergeSort(arr, start, mid, temp);
mergeSort(arr, mid + 1, end, temp);
merge(temp, start, mid, end, temp);
}
return temp;//what do i return
}
public static void main(String[] args) {
int[] arr = {37, 27, 43, 3, 9, 81, 10};//3,9,10,27,39,43
int length = sortedmerge.length/2-1;//-1 offset for mid
arrayToString(mergeSort(arr,0,arr.length,new int[arr.length]));
}
if (start < end) {
int mid = ((start + end) / 2) - 1; //offset for mid for odd size
mergeSort(arr, start, mid, temp);
mergeSort(arr, mid + 1, end, temp);
merge(temp, start, mid, end, temp);
}
start would never be less than mid so your first invokation of mergeSort(arr, start, mid, temp); seems to enter the infine loop which causes stackoverflow.
This is my quicksort Code. It gives me a wrong answer but i think my partition function is correct.
public class Quick_Sort {
public static void main(String[] args)
{
int a[] = {99,88,5,4,3,2,1,0,12,3,7,9,8,3,4,5,7};
quicksort(a, 0, a.length-1);
}
static int partition(int[] a, int low , int hi)
{
int pivot = hi;
int i =low;
int j = hi-1;
while(i<j)
{
if(a[i]<=a[pivot])
{
i++;
}
if(a[i]>a[pivot])
{
if((a[i]>a[pivot]) && (a[j]<=a[pivot]))
{
int temp= a[i];
a[i]=a[j];
a[j]=temp;
i++;
}
if(a[j]>a[pivot])
{
j--;
}
}
}
int temp= a[i];
a[i]=a[pivot];
a[pivot]=temp;
return i;
}
static void quicksort(int[] a, int low, int hi)
{
if(low>=hi)
{
return;
}
int split = partition(a, low, hi);
quicksort(a, low, split-1);
quicksort(a, split+1, hi);
}
}
This is the final output:
1 0 3 2 3 4 4 5 5 7 3 7 8 9 12 88 99
Tried dry running it, couldn't see the error
In your partition method you have assigned j to hi - 1. It should be set to hi only.
static int partition(int[] a, int low , int hi)
{
int pivot = hi;
int i =low;
// int j = hi-1; // CHANGE THIS TO
int j = hi; // THIS
while(i<j)
I got this output after I made that change:
[0, 1, 2, 3, 3, 3, 4, 4, 5, 5, 7, 7, 8, 9, 12, 88, 99]
Hope this helps!
This is C# code:
public void RecursiveQuickSort(int[] array, int start, int end)
{
if (start < end)
{
int pivot = start;
int left = start + 1;
int right = end;
while (true)
{
while (array[left] <= array[pivot] && left < right)
left++;
while (array[right] > array[pivot] && left < right)
right--;
if (left < right)
{
Swap(array, left, right);
}
else
{
pivot = (array[pivot] > array[left]) ? left : left - 1;
Swap(array, start, pivot);
RecursiveQuickSort(array, start, pivot - 1);
RecursiveQuickSort(array, pivot + 1, end);
return;
}
}
}
}
private void Swap(int[] array, int index1, int index2)
{
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
This is a very good implementation and is much more Java standard. Maybe you want to take a look here, obviously all credits go to the original author.
http://www.vogella.com/tutorials/JavaAlgorithmsQuicksort/article.html
this is how I made it C:
private static List<Integer> recursive_quick_sort (List<Integer> list){
if (list.size()< 2){
return list;
}else {
int pivot = list.get(0);
List<Integer> less = list.stream().filter(element -> element < pivot ).collect(Collectors.toList());
List <Integer> greater = list.stream().filter(element -> element > pivot ).collect(Collectors.toList());
List<Integer> newList = Stream.of(recursive_quick_sort(less),List.of(pivot),recursive_quick_sort(greater))
.flatMap(Collection::stream)
.collect(Collectors.toList());
return newList;
}
}