Apparently the sort method is causing a stackoverflowerror. Why?
public static void quickSort(int[] a, int low, int high) {
if (a.length > 1) {
int middle = a.length / 2;
int size = a.length - middle;
int pivot = a[middle];
sort(a, low, middle, high);
quickSort(a, low, middle);
quickSort(a, middle + 1, high);
}
}
public static void sort(int[] a, int low, int middle, int high) {
boolean b = true;
int i = low;
int j = high;
for (int x = 0; x < middle + 1; x++)
if (a[x] <= a[middle])
i++;
for (int x = middle + 1; x < high + 1; x++)
if (a[x] > a[middle])
j--;
if (i != middle && j != middle + 1) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
b = false;
}
if (b == false)
sort(a, low, middle, high);
return;
}
}
note here in sort function.
if (b == false) {
sort(a, low, middle, high);
}
this b always false. and you do no change in low, middle, hifg values. so sort function call recursive as it is. so no change at all, function call repeat and stackoverflow will occure.
Related
I've the following implementation for quicksort, but trying to transfer it to quickselect fails.
class Solution {
public static void main(String[] args) {
for (int i = 1; i < 5; i++) {
int[] arr = new int[]{9,8,7,1,2,3,6,5,4};
System.out.println(quicksort(arr, i));
}
}
private static int quicksort(int[] arr, int k) {
return quicksort(arr, 0, arr.length - 1, k);
}
private static int quicksort(int[] arr, int low, int high, int k) {
int p = partition(arr, low, high);
/* Doesnt work:
if (p == k) {
return arr[k];
} else if (p < k) {
return quicksort(arr, p+1, high, k);
} else {
return quicksort(arr, low, p-1, k);
}
*/
}
private static int partition(int[] arr, int low, int high) {
int i = low;
int j = high;
int pivot = arr[low + (high - low) / 2];
while (true) {
while (arr[i] < pivot) {
i++;
}
while (arr[j] > pivot) {
j--;
}
if (i < j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
} else {
return j;
}
}
}
}
It feels like the information that everything from 0..p is smaller or equal to arr[p] and vice-versa does not help at all.
Example:
9,8,7,1,2,3,6,5,4, after partition: 2, 1, 7, 8, 9, 3, 6, 5, 4 with p = 1 (choosen pivot was 2). So I know the first and second lowest value is in 0..1 range. But it isn't sorted, so I cannot simply say if (p == k-1) return arr[p], because it isn't guaranteed that arr[p] is the max of that half, just that everything in that half is less than the choosen pivot.
Any idea how I can make it work?
I have a mergesort which needs to switch into insertionSort at a specific number, which is my threshold. But my threshold can only be 1, 2 or 3 because in any other cases my mergesort becomes very slow. I cant seem to get the Code to work together.
Here is my code:
public class InsertionSort {
// I haven't found the right Threshold yet, but it should work with any number between 1-100.
public final static int M = 16;
private void Merge(int arr[], int left, int mid, int right) {
int size1 = mid - left + 1;
int size2 = right - mid;
int LeftArray[] = new int[size1];
int RightArray[] = new int[size2];
for (int i = 0; i < size1; ++i) {
LeftArray[i] = arr[left + i];
}
for (int j = 0; j < size2; ++j) {
RightArray[j] = arr[mid + 1 + j];
}
int i = 0;
int j = 0;
int k = left;
while (i < size1 && j < size2) {
if (LeftArray[i] <= RightArray[j]) {
arr[k] = LeftArray[i];
i++;
} else {
arr[k] = RightArray[j];
j++;
}
k++;
}
while (i < size1) {
arr[k] = LeftArray[i];
i++;
k++;
}
while (j < size2) {
arr[k] = RightArray[j];
j++;
k++;
}
}
public void MergeSort(int arr[], int left, int right, int M) {
if ( left < right ) {
int mid = (left + right) / 2;
MergeSort(arr, left, mid, M);
MergeSort(arr, (mid+1), right, M);
Merge(arr, left, mid, right);
} else if ((right - left + 1) <= M) {
insertion_sort(arr, left, right);
}}
static void printArray(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; ++i)
System.out.print(arr[i] + " ");
System.out.println();
}
static int[] readIntfile(String filename) throws Exception {
// Read file into a byte array, and then combine every group of four bytes to an
// int. (Not
// the standard way, but it works!)
byte[] bytes = Files.readAllBytes(Paths.get(filename));
int[] ints = new int[bytes.length / 4];
for (int i = 0; i < ints.length; i++) {
for (int j = 0; j < 4; j++) {
ints[i] += (bytes[i * 4 + j] & 255) << (3 - j) * 8;
}
}
return ints;
}
public static void insertion_sort(int a[], int left, int right) {
int j;
for (int i = left; i <= right; i++) {
int tmp = a[i];
for (j = i; j > 0 && tmp < a[j - 1]; j--) {
a[j] = a[j - 1];
}
a[j] = tmp;
}
}
public static void main(String args[]) throws Exception {
// I have texfile named this with 1000000 numbers
int arr[] = readIntfile("smallints");
// you can also try with this array for example
// int arr[] = {3, 6, 4, 8, 500, 1, 5, 10, 7, 9, 0, 2, 100, 300, 1000, 20, 13, 17, 55, 93};
InsertionSort insert = new InsertionSort();
long before = System.currentTimeMillis();
insert.MergeSort(arr, 0, arr.length-1, M);
long after = System.currentTimeMillis();
printArray(arr);
System.out.println("\n" + "Done " + ((after - before) / 1000.0 + " sek"));
}
}
public void MergeSort(int arr[], int left, int right, int M) {
if ( left < right ) {
int mid = (left + right) / 2;
MergeSort(arr, left, mid, M);
MergeSort(arr, (mid+1), right, M);
Merge(arr, left, mid, right);
} else if ((right - left + 1) <= M) {
insertion_sort(arr, left, right);
}}
You have a serious problem here. You have a class global variable, M, which is your insertion sort threshold, and you have a parameter, M, which is the length of the subarray you want to sort. The parameter is going to shadow the class global. Basically, your public final static int M = 16; is never seen inside the MergeSort method.
Also, if left is not less than right, then there's nothing to sort. I think you want something like this:
public final static int insertionThreshold = 16;
public void MergeSort(int arr[], int left, int right, int M) {
if ( left < right ) {
if (left - right <= insertionThreshold) {
insertion_sort(arr, left, right);
else {
int mid = (left + right) / 2;
MergeSort(arr, left, mid, M);
MergeSort(arr, (mid+1), right, M);
Merge(arr, left, mid, right);
}
}
}
I am trying to implement a merge sort function, and am receiving a StackOverflowError exception when trying to run it. I saw another question similar to mine, with the answer about changing how the midpoint is calculated. I tried to change the midpoint, but am still getting the same stackoverflow error.
Thanks for looking.
public static void mergeSort(int [] arr, int low, int high) {
if (low < high) {
int mid = (low + high)/2;
mergeSort(arr, low, mid + 1);
mergeSort(arr, mid, high);
merge(arr, low, mid, high);
}
}
public static void merge(int [] arr, int low, int mid, int high) {
int n1 = mid - low + 1;
int n2 = high - mid;
int [] leftArr = new int[n1];
int [] rightArr = new int[n2];
for (int i = 0; i < n1; i++) leftArr[i] = arr[low + i];
for (int j = 0; j < n2; j++) rightArr[j] = arr[mid + j + 1];
int i = 0;
int j = 0;
int k = 1;
while (i < n1 && j < n2) {
if (leftArr[i] < rightArr[j]) {
arr[k] = leftArr[i++];
}
else {
arr[k] = rightArr[j++];
}
k++;
}
while (i < n1) arr[k++] = leftArr[i++];
while (j < n2) arr[k++] = rightArr[j++];
}
You implemented your mergesort function wrong.it should look like this
if (low < high) {
int mid = (low + high)/2;
mergeSort(arr, low, mid -1);
mergeSort(arr, mid, high);
merge(arr, low, mid, high);
}
And in the merge function you have initialised
k=1;
but it should be
k=low;
because if you will initialise k=1 everytime then it will override the array elements.
I'm trying to implement quicksort using the median of three algo and it fails a unit test I wrote related to a small partition. I changed my earlier partition and now it passes one of the tests it used to fail, but still fails the one at the bottom:
My code is:
public class QuickSort {
static void swap(int[] A, int i, int j) {
int tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
static final int LIMIT = 15;
static int partition(int[] a, int left, int right){
int center = (left + right) / 2;
if(a[center] < (a[left]))
swap(a,left,center);
if(a[right-1] < a[left])
swap(a,left,right);
if(a[right-1] < a[center])
swap(a,center,right);
swap(a,center,right - 1);
return a[right - 1];
}
static void quicksort(int[] a, int left, int right){
if(left + LIMIT <= right){
int pivot = partition(a,left,right);
int i = left;
int j = right - 1;
for(;;){
while(a[++i] < pivot){}
while(a[--j] > pivot){}
if(i < j)
swap(a,i,j);
else
break;
}
swap(a,i,right - 1);
quicksort(a,left,i-1);
quicksort(a,i+1,right);
}
else{
insertionSort(a);
}
}
public static void insertionSort(int[] a){
int j;
for(int p = 1; p < a.length; p++){
int tmp = a[p];
for(j = p; j > 0 && tmp < a[j-1]; j--)
a[j] = a[j-1];
a[j] = tmp;
}
}
}
This test fails:
public void smalltest() throws Exception {
int[] Arr_orig = {3,9,8,2,4,6,7,5};
int[] Arr = Arr_orig.clone();
int pivot = QuickSort.partition(Arr, 0, Arr.length);
for (int i = 0; i != pivot; ++i)
assertTrue(Arr[i] <= Arr[pivot]); //fails!
for (int i = pivot + 1; i != Arr.length; ++i)
assertTrue(Arr[pivot] < Arr[i]);
}
There is a conflict between using right-1 and right in this sequence:
if(a[right-1] < a[left])
swap(a,left,right);
You need to decide if right is going to be the index to the last element, or 1 + index to the last element (an "ending" index).
There may be other problems, but this is the first one I noticed.
My code works properly (to my knowledge) up until my input array size (a.length) is around 62,000 at which time I consistently get a StackOverFlowError. I previously had used 2 recursive calls to quicksort (less than, and greater than the pivot q) and then I switched to tail recursion. As you can see, I'm selecting the pivot to be the value at the end of the array. I know this isn't the best way to choose a pivot, but I still shouldn't be seeing StackOverFlowErrors with an array size this small, right? What could be causing this? Thanks in advance! Here's my code:
public static void quicksort(int[] a, int p, int r)
{
int q;
while (p < r)
{
q = partition(a, p, r);
quicksort(a, p, q - 1);
p = q + 1;
}
}
public static int partition(int[] a, int p, int r)
{
int j = p - 1;
int x = a[r];
for (int i = p; i < r; i++)
{
if (a[i] <= x)
{
j++;
swap(a, i, j);
}
}
j++;
swap(a, j, r);
return j;
}
private static void swap(int[] a, int i, int j)
{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
The worst-case input (sorted order) makes quicksort Θ(n^2). Partition always puts a single element on one side of the partition (Cormen et al.). By randomizing the sort (choosing a random pivot) no particular input elicits its worst-case behavior.
import java.util.Random;
public class Quicksort
{
private static Random rand = new Random();
public static void quicksort(int[] arr, int left, int right)
{
if (left < right)
{
int pivot = randomizedPartition(arr, left, right);
quicksort(arr, left, pivot);
quicksort(arr, pivot + 1, right);
}
}
private static int randomizedPartition(int[] arr, int left, int right)
{
int swapIndex = left + rand.nextInt(right - left) + 1;
swap(arr, left, swapIndex);
return partition(arr, left, right);
}
private static int partition(int[] arr, int left, int right)
{
int pivot = arr[left];
int i = left - 1;
int j = right + 1;
while (true)
{
do
j--;
while (arr[j] > pivot);
do
i++;
while (arr[i] < pivot);
if (i < j)
swap(arr, i, j);
else
return j;
}
}
private static void swap(int[] arr, int i, int j)
{
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
// Sort 100k elements that are in reversed sorted order
public static void main(String[] args)
{
int arr[] = new int[100000];
for (int i = 0; i < arr.length; i++)
arr[i] = arr.length - i;
System.out.println("First 20 elements");
System.out.print("Before sort: ");
for (int i = 0; i < 20; i++)
System.out.print(arr[i] + " ");
System.out.println();
quicksort(arr, 0, arr.length - 1);
System.out.print("After sort: ");
for (int i = 0; i < 20; i++)
System.out.print(arr[i] + " ");
System.out.println();
}
}
Given the right input, your implementation will recurse once for every single element of the array. 60,000 recursive calls could easily be enough to overflow the stack in Java in the default configuration.