Quick Sort Algorithm ArrayOutOfBounds [duplicate] - java

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 am trying to grasp a better understanding of the Quick Sort Algorithm I understand what happens underneath the code.
But when I write it I am getting the famous java.lang.ArrayIndexOutOfBoundsException.
I can not see where and have been messing around with the indexes of the arrays for sometime now but to no avail.
Here is my code
package QuickSort;
public class quickSort {
public static void main(String[] args) {
int[] array = {9,4,6,3,7,1,2,11,5};
printArray(array);
//10 sort(array, 0, array.length - 1);
}
//Partition Method Algorithm
static int partition(int arr[], int start, int end) {
//Start pivot at the last Index
int pivot = arr[end];
//The partition index checks if the number which was last switched
//19 int partitionIndex = start;
for(int i = start; start < end; i++) {
if(arr[i] <= pivot) {
int temp = arr[i];
arr[i] = arr[partitionIndex];
arr[partitionIndex] = temp;
partitionIndex++;
}
}
int temp = arr[partitionIndex];
arr[partitionIndex] = end;
arr[end] = temp;
return partitionIndex;
}
//Recursive function:
//piviotIndex is returned and keeps track of where the partition ends for the LHS
//PivotIndex keeps track of where the RHS partition starts
static void sort(int arr [], int start, int end) {
if(start<end) {
//52 int pivotIndex = partition(arr, 0, end);
partition(arr, start, pivotIndex-1);
partition(arr, pivotIndex+1, end);
}
}
static void printArray(int arr[]) {
for(int i : arr)
System.out.print(i + ", ");
}
}
The error message I am getting is
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 9
at QuickSort.quickSort.partition(quickSort.java:19)
at QuickSort.quickSort.sort(quickSort.java:52)
at QuickSort.quickSort.main(quickSort.java:10)

Change
for(int i = start; start < end; i++) {
to
for(int i = start; i < end; i++) {

If you really want to check start < end condition then you could do something like this in your forloop, to avoid ArrayIndexOutOfBoundsException exception
for(int i = start; i < end && start < end; i++)
or if not then
for(int i = start; i < end ; i++)
But I could see still your code is not printing sorted array

Related

Randomized QuickSort IndexOutOfBounds exception [duplicate]

This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 1 year ago.
this is the QuickSort Randomized that I've come up with, but it constantly throws out IndexOutOfBounds exception. Could I have some help with it? Thanks!
import java.util.Random;
public class QuickSort {
void quickSort(int[] A, int start, int end) { // Initially: start = 0, end = n-1
while (start < end) {
int iOfPartition = randomisedPartition(A, start, end);
if (iOfPartition - start < end - iOfPartition) {
quickSort(A, start, iOfPartition - 1);
start = iOfPartition + 1;
} else {
quickSort(A, iOfPartition + 1, end);
end = iOfPartition - 1;
}
}
}
int randomisedPartition(int[] A, int start, int end) {
Random rng = new Random();
int randomNum = rng.nextInt(end + 1 - start) + start;
swap(A, A[randomNum], A[start]);
return hoarePartition(A, start, end);
}
int hoarePartition(int[] A, int start, int end) {
int pivot = A[start];
int i = start;
int j = end;
while (i < j) {
while (A[i] <= pivot && i < end) i++;
while (A[j] > pivot && j > start) j--;
if (i < j) swap(A, A[i], A[j]);
}
swap(A, A[start], A[j]);
return j;
}
void swap(int[] A, int i, int j) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
}
I keep getting an arrayindexoutofbounds error.
I echo the sentiment of the comment above, you should learn to use the debugger or print statements to try to piece together what is happening.
Still, I couldn't resist investigating.
Check out what you are doing here in the call to swap. You are taking the value which is in the randomNum position with A[randomNum]
swap(A, A[randomNum], A[start]); // incorrectly indexing here
But then inside swap, you are repeating the process, and taking the value at the A[A[randomNum]] which does not necessarily exist.
int temp = A[i]; // indexing here again
So your problem is that you are incorrectly indexing twice. You should use [] only in the swap function, not in the randomisedPartition function. randomisedPartition should send swap indexes, not indexed values.
How did I figure this out ?
I tried a call with very simple data
int data[] = {5,3,4};
new Example().quickSort(data, 0, 2);
and got an index out of bounds 5 error. That's how you debug.

array index out of bounds exception in this merge sort problem [duplicate]

This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 1 year ago.
I was practicing to do merge sort. This is the problem i got, it shows array index out of bounds, i checked the for loop and modified with < which was before <=, i dont know how to resolve
public class MergeSortProblem {
public static void merge(int[] arr, int[] res, int low, int mid, int high) {
int i = low, k= low, j=mid+1;
while(i<=mid && j<=high) {
if(arr[i] <= arr[j]) {
res[k++] = arr[i++];
}
else {
res[k++] = arr[j++];
}
}
while(i<=mid) {
res[k++] = arr[i++];
}
while(j<=high) {
res[k++] = arr[j++];
}
for(i =low; i<=high; i++ ) {
arr[i] = res[k];
}
}
public static void divideArray(int[] arr, int[] res, int low, int high) {
while(low == high) {
return;
}
int mid = (low + high)/2 ;
divideArray(arr, res, low,mid);
divideArray(arr,res, mid+1, high);
merge(arr,res,low,mid,high);
}
public static void main(String[] args) {
int[] array = {6,10,5,7,6,8,3,80};
int size = array.length;
int start = 0;
int[] result = {};
divideArray(array,result,start,size);
}
}
why am i getting array index out of bounds exception?
for(i =low; i<=high; i++ ) {
arr[i] = res[k];
}
By looking at your code, this will return an array out of bounds exception. This happens because high is set to the arrays length 8 and you are looping from low to 8 because of the <= (the highest index of the array will be 7). It is always a good idea to use just < when looping through an array when using array.length
I recommend checking out Geeks For Geeks. They have a lot of examples of common algorythems like merge sort.

Debugging : Mergesort

Trying to implement merge sort in Java. I've gone over my code a bunch in my head and I feel like it should be working, but obviously I'm doing something wrong. Heres the code
public static void mergeSort(int[] input, int start, int end) {
if (end - start < 2)
return;
int mid = (start + end) / 2;
mergeSort(input, start, mid);
mergeSort(input, mid + 1, end);
merge(input, start, mid, end);
}
public static void merge(int[] input, int start, int mid, int end) {
if (input[mid - 1] <= input[mid])
return;
int i = start;
int j = mid;
int tempIndex = 0;
int[] temp = new int[end - start]; //combined size of both arrays being merged
/*if i is >= mid, then that means the left portion of the array is done being sorted
and vice versa if j >= end. Once this happens, we should be able to
just copy the remaining elements into the temp array
*/
while (i < mid && j < end) {
temp[tempIndex++] = (input[i] <= input[j]) ? input[i++] : input[j++];
}
//Copying left over elements in left portion
while (i < mid)
temp[tempIndex++] = input[i++];
//Copying left over elements in right portion
while (j < end)
temp[tempIndex++] = input[j++];
//Copy the sorted temp array into the original array
//This is where I think I must be messing up
for (int k = 0; k < temp.length; k++) {
input[start + k] = temp[k];
}
}
I think it must be that im not copying correctly the temp array with the sorted elements back into the original array, but I'm not sure. I wrote comments on my code explaining my logic.
Take a look at the following changes:
Calculating mid
int mid = start + (end - start) / 2;
Assigning pointers i,j correctly.
int i = start;
int j = mid+1;
Correct size of temp array.
int [] temp = new int[end-start+1];
Corrected while loops condition in the code.
class Solution{
public static void mergeSort(int[] input, int start, int end)
{
if (end == start ) return;
int mid = start + (end - start) / 2;
mergeSort(input, start, mid);
mergeSort(input, mid+1, end);
merge(input, start, mid, end);
}
public static void merge(int[] input, int start, int mid, int end) {
// No Need of the under mentioned instruction
// if(input[mid-1] <= input[mid]) return;
int i = start;
int j = mid+1;
int tempIndex = 0;
int [] temp = new int[end-start+1]; //combined size of both arrays being merged
/*if i is >= mid, then that means the left portion of the array is done being sorted and vice versa if j >= end. Once this happens, we should be able to just copy the remaining elements into the temp array */
while(i <= mid && j <= end){
temp[tempIndex++] = (input[i] <= input[j]) ? input[i++] : input[j++];
}
//Copying left over elements in left portion
while(i <= mid)
temp[tempIndex++] = input[i++];
//Copying left over elements in right portion
while(j <= end)
temp[tempIndex++] = input[j++];
//Copy the sorted temp array into the original array
//This is where I think I must be messing up
for(int k = 0; k < temp.length; k++){
input[start+k] = temp[k];
}
}
public static void main(String[] args){
int[] input = {9,4,6,8,5,7,0,2};
mergeSort(input,0,7);
for(int i : input)
System.out.println(i);
}
}

Java QuickSort Best Case Array Generation

I've been banging my head on the table on this one.
I need to create an n sized array that is optimized for QuickSort Partition. It will be used to demonstrate the growth of QuickSort's best case. I know that for best case, QuickSort must select a pivot that divides the array in half for every recursive call.
I cannot think of a way to create an n-sized optimized array to test. Any help would be greatly appreciated.
Here is the algorithm in Java.
public class QuickSort {
private int length;
private void quickSort(int[] a, int p, int r) {
if (p < r) {
int q = partition(a, p, r);
quickSort(a, p, q - 1);
quickSort(a, q + 1, r);
}
}
private int partition(int[] a, int p, int r) {
int x = a[r];
int i = p - 1;
for (int j = p; j < r; j++) {
if (a[j] <= x) {
i++;
exchange(a, i, j);
}
}
exchange(a, i + 1, r);
return i + 1;
}
public void exchange(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
QuickSort(int[] a) {
if (a == null || a.length == 0) {
return;
}
length = a.length;
quickSort(a, 0, length - 1);
}
}
I know this is an old question, but I had the same question and finally developed a solution. I'm not a Java programmer, so don't blame me for Java code issues, please. I assumed that the quicksort algorithm always takes the first item as a pivot when partitioning.
public class QuickSortBestCase
{
public static void generate(int[] arr, int begin, int end)
{
int count = end - begin;
if(count < 3)
return;
//Find a middle element index
//This will be the pivot element for the part of the array [begin; end)
int middle = begin + (count - 1) / 2;
//Make the left part best-case first: [begin; middle)
generate(arr, begin, middle);
//Swap the pivot and the start element
swap(arr, begin, middle);
//Make the right part best-case, too: (middle; end)
generate(arr, ++middle, end);
}
private static void swap(int[] arr, int i, int j)
{
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
private static void fillArray(int[] arr)
{
for(int i = 0; i != arr.length; ++i)
arr[i] = i + 1;
}
private static void printArray(int[] arr)
{
for(int item : arr)
System.out.print(item + " ");
}
public static void main(String[] args)
{
if(args.length == 0)
return;
int intCount = Integer.parseInt(args[0]);
int[] arr = new int[intCount];
//We basically do what quicksort does in reverse
//1. Fill the array with sorted values from 1 to arr.length
fillArray(arr);
//2. Recursively generate the best-case array for quicksort
generate(arr, 0, arr.length);
printArray(arr);
}
}
This program produces the same output for the array of 15 items, as described here: An example of Best Case Scenario for Quick Sort. And in case someone needs a solution in C++:
template<typename RandomIterator,
typename Compare = std::less<typename RandomIterator::value_type>>
void generate_quicksort_best_case_sorted(RandomIterator begin, RandomIterator end)
{
auto count = std::distance(begin, end);
if (count < 3)
return;
auto middle_index = (count - 1) / 2;
auto middle = begin + middle_index;
//Make the left part best-case first
generate_quicksort_best_case_sorted(begin, middle);
//Swap the pivot and the start element
std::iter_swap(begin, middle);
//Make the right part best-case, too
generate_quicksort_best_case_sorted(++middle, end);
}
template<typename RandomIterator,
typename Compare = std::less<typename RandomIterator::value_type>>
void generate_quicksort_best_case(RandomIterator begin, RandomIterator end)
{
{
auto current = begin;
RandomIterator::value_type value = 1;
while (current != end)
*current++ = value++;
}
generate_quicksort_best_case_sorted(begin, end);
}

How to avoid StackOverflowError caused by the number of recursion calls in Java?

I want to solve this problem: https://www.hackerrank.com/challenges/find-median ,i.e. find the median element in unsorted array. To do this I perform quickselect algorithm.
My program works correctly on my computer. However when I submitted in the system it gave me StackOverflowError. I think this is because of the depth of the recursion calls. I guess I make too many recursion calls than Java allows (the error is caused by a test case with 10 001 numbers). Can someone suggest me how to avoid this?
This is my code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class FindMedian {
static int res;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
String line1 = br.readLine();
int N = Integer.parseInt(line1);
String[] line2 = br.readLine().split(" ");
int[] arr = new int[N];
for (int i = 0; i < N; i++) {
arr[i] = Integer.parseInt(line2[i]);
}
selectKth(arr, 0, N - 1);
System.out.println(res);
}
public static void selectKth(int[] arr, int start, int end) {
// it is written to select K-th element but actually
// it selects the median element
if (start >= end) {
res = arr[start];
return;
}
int pivot = arr[start];
int n = arr.length - 1;
int i = start + 1;
int j = end;
while (i <= j) {
while (arr[i] <= pivot) {
i++;
}
while (pivot < arr[j]) {
j--;
}
if (i < j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
}
int tmp = arr[j];
// j is the index of the last element which is bigger or equal to pivot
arr[j] = pivot;
arr[start] = tmp;
if (n / 2 <= j) {
selectKth(arr, start, j);
} else {
selectKth(arr, i, end);
}
}
}
A basic concept of IT science is to replace recursion with iteration. By using iteration you'll never run into "recursion too deep" errors. Every problem can be solved either by recursion or by iteration.
See my link for details.
http://www.refactoring.com/catalog/replaceRecursionWithIteration.html
Since you only call selectKth at the very end of itself (it's practically tail recursive already), it's trivial to unroll your recursion into an iteration.
func foo(param) {
if (param == bar) //bailout condition
return;
x = doStuff(param); //body of recursive method
foo(x); //recursive call
}
Can be rewritten as
func foo(param) {
x = param;
while ( x != bar ) {
x = doStuff( x );
}
}
In your case the only tricky bit is the last if:
if(n/2 <= j){
selectKth(arr, start, j);
}
else{
selectKth(arr, i, end);
}
So your method will look like this:
public static void selectKth(int[] arr, int start, int end) { //it is written seclect K-th element but actually it selects the median element
while( start < end ) {
//method body as is up to the last `if`
if(n/2 <= j) { //instead of recursion we just adjust start and end, then loop
end = j;
}
else{
start = i;
}
}
res = arr[start];
}

Categories