StackOverFlow error for QuickSort Algorithm - java

I am getting a StackOverflowError for this code. It says lines 184/185, which is where I initialize the split position (see below) and call the first recursive quickSort method. I can see that the code is having trouble exiting from the recursion, but I'm not sure where that is happening. Each time I call quickSort, it is on a smaller partition.
import java.util.*;
public class java2{
public static int MAXINT = 10000;
public static int[] intArray = new int[MAXINT];
public static int index;
public static long comparisons;
public static void main(String[] args)
{
System.out.println("SORTING ALGORITHM: Quicksort");
// Create a random array of integers and sort using the CombSort algorithm
// Print the number of items and comparisions
for(index = 10; index <= 10000; index = index * 10)
{
if (index == 10)
for(int i = 0; i < index; i++)
System.out.print(intArray[i] + " ");
comparisons = 0;
generate(intArray, index);
quickSort(intArray, 0, index - 1);
output(comparisons);
}
}
// Generate an array of random values between 0 and 10000
public static void generate(int[] valueArray, int count)
{
Random generator = new Random();
for(int temp = 0; temp < count; temp++)
{
valueArray[temp] = generator.nextInt(MAXINT) + 1;
}
}
// Print the number of values in the array and the number of comparisons
public static void output(long count)
{
System.out.println("Number of values in array: " + index);
System.out.println("Number of comparisons required: " + count);
System.out.println();
}
//Swap the given values and then assign them to the correct place in the array
public static void swap(int[] value, int i, int j)
{
int temp = value[i];
value[i] = value[j];
value[j] = temp;
}
//Implement Quicksort algorithm
public static void quickSort(int[] value, int startIndex, int endIndex)
{
int r = endIndex;
int l = startIndex;
int s;
if (l < r)
{
s = partition(intArray, l, r);
quickSort(intArray, l, s - 1); // StackOverflowError here
quickSort(intArray, s + 1, r);
}
}
//Partition an array into two parts
public static int partition(int[] value, int startIndex, int endIndex)
{
int r = endIndex;
int l = startIndex;
int p = value[l];
int i = l;
int j = r + 1;
while(i < j)
{
while(value[i] < p)
{
i++;
comparisons++;
}
while(value[j] > p)
{
j--;
comparisons++;
}
swap(value, i, j);
}
swap(value, i, j);
swap(value, l, j);
return j;
}
} // end main

Here are a few things to get you started with debugging.
You haven't posted your swap, but it's almost certainly incorrect. The way you're using it, its prototype would be void swap(int, int, int, int) which means it cannot have any effect on the value array. Try something like this:
public static void swap(int[] value, int i, int j) {
int temp = value[i];
value[i] = value[j];
value[j] = temp;
}
and use it like this:
swap(value, i, j);
Next, get the length=10 case correct. Print out the full array before and after sort, verify that the output is correct. When I run your code on an all zero array I get an infinite loop.
Next, if you're still having problems, add print statements!

By restructuring the partition method, the problem has been fixed:
public static int partition(int[] value, int p, int r)
{
int x = value[p];
int i = p - 1;
int j = r + 1 ;
while (true)
{
do
{
j--;
comparisons++;
}
while (value[j] > x);
do
{
i++;
comparisons++;
}
while (value[i] < x);
if (i < j)
{
swap(value, i, j);
}
else
return j;
}
}

Related

Why do we use two different loop variables while sorting an array using merge sort?

I was learning to merge sort an integer array, when I noticed that while copying the sorted array elements to the original array, we need two separate loop variables to run simultaneously, while the values at those indices are copied to the original array. Here is the code for reference:
class MergeSort {
public static void sort(int arr[], int si, int ei, int mid) {
int merged[] = new int[ei - si + 1];
int index1 = si; // tracks the first array
int index2 = mid + 1; // tracks the second array
int i = 0;
while (index1 <= mid && index2 <= ei) {
if (arr[index1] <= arr[index2]) {
merged[i++] = arr[index1++];
} else {
merged[i++] = arr[index2++];
}
} // end of while
while (index1 <= mid) {
merged[i++] = arr[index1++];
}
while (index2 <= ei) {
merged[i++] = arr[index2++];
}
// to copy merged[] to arr[]
int j = si;
for (i = 0; i < merged.length; i++, j++) {
arr[j] = merged[i];
}
} // end sort()
public static void divide(int arr[], int si, int ei) {
// base case
if (si >= ei) {
return;
} // end of base case
int mid = si + (ei - si) / 2; // same as (ei-si)/2 but with less space complexity
divide(arr, si, mid);
divide(arr, mid + 1, ei);
sort(arr, si, ei, mid);
} // end of divide
public static void main(String args[]) {
int arr[] = { 1, 8, 0, 7, -4 };
int n = arr.length;
divide(arr, 0, n - 1);
for (int i = 0; i < n; i++) {
System.out.print(arr[i] + " ");
} // end of for
} // end of main
} // end of class
Notice that while copying the values of the array merged[] to the array arr[], we are using two separate variables i and j. I did try using only one loop variable, which went like:
for (int i = 0; i < arr.length; i++) {
arr[i] = merged[i];
}
but received an incorrect output. If anyone knows why we need two separate variables for the operation, please let me know. Thank you :)
You could use a single variable in this final loop, but you must add the offset of the start of the slice in the destination array:
for (int i = 0; i < arr.length; i++) {
arr[si + i] = merged[i];
}

I am trying to count the number of comparison's in a heap sort and a quick sort

The purpose of this project is to create two arrays of random numbers and run a quick sort and heap sort of them. Keep track of the number of comparison's and then compare them. Both sorts work, but my heap sort wont keep track of the comparison's. it just says 0. My quick sort works and puts the comparisons in an array. How do i fix this?
package sorting;
import java.util.Arrays;
//import java.util.Random;
import java.util.*;
public class project2
{
static int [] heap_sort_comparison = new int[21];
static int [] quick_sort_comparison = new int[21];
static int [] array1 = new int [20];
static int [] array2 = new int [20];
static int compares = 0;
static int heap_compares = 0;
private static void quickSort(int[] array1, int l, int h) {
if(l < h ) {
compares++;
int position = partition(array1, l, h);
quickSort(array1,l, position -1);
quickSort(array1, position +1, h);
}
}
private static int partition(int[] array1, int i, int j) {
int pivot = array1[j] -1;
int small = i -1;
for(int k = i; k < j; k++) {
if(array1[k] <= pivot) {
compares++;
small++;
swap(array1, k, small);
}
}
swap(array1, j, small + 1);
//System.out.println("Pivot = " + array1[small + 1]);
print_quick_sort(array1);
return small + 1;
}
public static void swap(int[] array1, int a, int b) {
int temp;
temp = array1[a];
array1[a] = array1[b];
array1[b] = temp;
}
public static void print_quick_sort(int[] array1) {
for(int i = 0; i < array1.length; i++) {
System.out.print(array1[i] + " ");
}
System.out.println();
}
//HEAP SORT
public void build(int array2[]) {
int length = array2.length;
for(int i = length/2-2; i >=0; i--) {
bubble_down(array2, i, array2.length-1);
heap_compares++;
}
for(int i = length-1; i>= 0; i--) {
swap2(array2, 0,i);
bubble_down(array2,i,0);
heap_compares++;
}
}
void bubble_down(int[] array2, int parent, int size) {
int left = parent*2+1;
int right = 2*parent+2;
int largest = 0;
if(left <= size && array2[left] > array2[largest]) {
largest = left;
heap_compares++;
}
if(right <= size && array2[right] > array2[largest]) {
largest = right;
heap_compares++;
}
if(largest != parent) {
swap2(array2,parent, largest);
bubble_down(array2,largest,size);
heap_compares++;
}
}
public static void swap2(int[] array2, int a, int b) {
int temp = array2[a];
array2[a] = array2[b];
array2[b] = temp;
}
public static void print_heap_sort(int[] array2) {
for(int i = 0; i < array2.length; i++) {
System.out.print(array2[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
for(int x = 0; x < 20; x++) {
for(int y = 0; y < 20; y++) {
for(int i = 0; i < array1.length; i++) {
array1[i] = array2[i]= (int)(Math.random()*20 + 0);
}
System.out.println("Numbers Generated in Array 1: " + Arrays.toString(array1));
System.out.println("");
System.out.println("Numbers Generated in Array 2: " + Arrays.toString(array2));
System.out.println("");
//quickSort
print_quick_sort(array1);
quickSort(array1, 0, array1.length -1);
System.out.println("The number of comparisons in quick sort: "+ compares);
System.out.println("=============================");
quick_sort_comparison[x] = compares;
compares = 0;
System.out.println("Array of quick sort comparison's: ");
System.out.println(Arrays.toString(quick_sort_comparison));
System.out.println("=============================");
//Heap Sort
System.out.println("Before Heap Sort: ");
System.out.println(Arrays.toString(array2));
heap_sort_comparison[y] = heap_compares;
heap_compares = 0;
HeapSort ob = new HeapSort();
ob.sort(array2);
System.out.println("Sorted array is (heap Sort): ");
print_heap_sort(array2);
System.out.println("=============================");
System.out.println("Array of heap sort comparison's: " + heap_compares);
System.out.println(Arrays.toString(heap_sort_comparison));
}
}
}
}
You do not even call the HeapSort method that you've built.
look here...
HeapSort ob = new HeapSort();
ob.sort(array2);
I think you are trying to use a built in sorting method from HeapSort class, So how do you think the counter heap_compares will increase!

Java Integer Array Rotation (Left)

I have a simple rotation function which takes an array and a number to rotate the numbers left
e.g. [1,2,3,4,5] & 2 - output: [3,4,5,1,2].
I want to know the most efficient way of completing this function, whether it would be to convert the int array into a string a splice it or whether to copy the array or to convert to an List<Integer>.
If anyone wants additional information please ask!
my solution at the moment:
static int[] rotLeft(int[] a, int d) {
int lengthOfArray = a.length;
int[] temp = new int[lengthOfArray];
for(int i = 0; i < lengthOfArray; i++){
int newLocation = (i + (lengthOfArray - d)) % lengthOfArray;
temp[newLocation] = a[i];
}
return temp;
}
Simple way to do it with O(n) complexity is as below along with handling of valid shifts int[] arr: is an int array, n=length of an array, d=how many shifts required.
public int[] leftRotate(int[] arr, int n, int d) {
int rot = 0;
int[] marr = new int[n];
if (d < 0 || d == 0 || d>n) {
return arr;
}
else {
for (int i = 0; i < n; i++) {
if (i < n - d) {
marr[i] = arr[i + d];
} else {
marr[i] = arr[rot];
rot++;
}
}
return marr;
}
}
public void GetArray(int[] arr, int n, int d) {
int[] arr1 = leftRotate(arr, n, d);
for (int j : arr1) {
System.out.println(j);
}
}
public static void main(String args[]) {
int[] arr = { 1,2,3,4,5 };
int n = arr.length;
Test2 obj = new Test2();
obj.GetArray(arr, n, 2);
}
Why don't you try this one
void Rotate(int arr[], int d, int n)
{
for (int i = 0; i < d; i++)
leftRotatebyOne(arr, n);
}
void leftRotatebyOne(int arr[], int n)
{
int i, temp;
temp = arr[0];
for (i = 0; i < n - 1; i++)
arr[i] = arr[i + 1];
arr[i] = temp;
}
and to call this invoke method like below
int arr[] = { 1, 2, 3, 4, 5 };
Rotate(arr, 2, 5);

Implementing a Randomized Selection Algorithm

I'm trying to implement the randomized selection algorithm that returns the K-th largest element in an array. The algorithm in the code below works when pivot is always set to equal the first element in the array. How do I get the code to work such that it finds the K-th largest using a randomly generated pivot point ?
import java.util.Random;
public class RandomizedKSelection {
private static Random generator = new Random();
public static int partition(int[] A, int start, int end) {
// start = generator.nextInt(end); This Line breaks the code
int pivot = A[start];
int pivotPosition = start++;
while (start <= end) {
// scan for values less than the pivot
while ((start <= end) && (A[start] < pivot)) {
start++;
}
// scan for values greater than the pivot
while ((end >= start) && (A[end] >= pivot)) {
end--;
}
if (start > end) {
// swap the end uncoformed
// element with the pivot
swap(A, pivotPosition, end);
}
else {
// swap unconformed elements:
// start that was not lesser than the pivot
// and end that was not larger than the pivot
swap(A, start, end);
}
}
return end;
}
#SuppressWarnings("unused")
// iterative version
private static int orderStatistic(int[] A, int k, int start, int end) {
int pivotPosition = partition(A, start, end);
while (pivotPosition != k - 1) {
if (k - 1 < pivotPosition) {
end = pivotPosition - 1;
}
else {
start = pivotPosition + 1;
}
pivotPosition = partition(A, start, end);
}
return A[k - 1];
}
public static int kthLargest(int[] A, int k) {
return orderStatistic(A, A.length - k + 1, 0, A.length - 1);
}
public static void swap(int[] A, int i, int j){
int temp = A[i];
A[i]= A[j];
A[j] = temp;
}
}
I've got a `partition implementation from wikibooks. I changed your code to use 0-based indices (you can find examples for 0-based indices more easily), you can wrap them if you like (see kthLargest1Based). Small randomized test arguments the validity of the algorithm.
import java.util.Arrays;
import java.util.Random;
public class RandomizedKSelection {
private static Random generator = new Random();
private static int partition(int[] array, int begin, int end) {
int index = begin + generator.nextInt(end - begin + 1);
int pivot = array[index];
swap(array, index, end);
for (int i = index = begin; i < end; ++ i) {
if (array[i] <= pivot) {
swap(array, index++, i);
}
}
swap(array, index, end);
return (index);
}
// iterative version
private static int orderStatistic(int[] A, int k, int start, int end) {
int pivotPosition = partition(A, start, end);
while (pivotPosition != k) {
if (k < pivotPosition) {
end = pivotPosition - 1;
} else {
start = pivotPosition + 1;
}
pivotPosition = partition(A, start, end);
}
return A[k];
}
public static int kthLargest(int[] A, int k) {
return orderStatistic(A, A.length - k - 1, 0, A.length - 1);
}
public static int kthLargest1Based(int[] A, int k) {
return kthLargest(A, k - 1);
}
public static int kthLargestSafe(int[] A, int k) {
Arrays.sort(A);
return A[A.length - k - 1];
}
public static void swap(int[] A, int i, int j) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
public static void main(String[] args) {
Random random = new Random();
for (int i = 0; i < 1000000; i++) {
int[] A = new int[1 + random.nextInt(1000)];
int max = 1 + random.nextInt(2 * A.length);
for (int j = 0; j < A.length; j++) {
A[j] = random.nextInt(max);
}
int k = random.nextInt(A.length);
if (RandomizedKSelection.kthLargest(A, k) != RandomizedKSelection.kthLargestSafe(A, k)) {
System.out.println("BUG");
}
}
}
}

HW Recursive Divide and Conquer Algorithm

I'm having a really big issue with finding the solution to my problem. I have to create a recursive, divide-and conquer algorithm that computes the length of the longest non-decreasing subsequence of elements in an array of integers. I have the following code, but it's not really working, any help would be much appreciated!!!
public class LongestSubSequence {
public static int getPartition(int[] a, int p, int r)
{
int mid = ((p+r)/2)-1;
int q=0;
int i = 1;
int j= mid+i;
int k = mid -i;
while (a[mid]<=a[j] && j < r)
{
q = j;
i++;
}
while (a[mid] >=a [k] && k > p)
{
q = k;
i++;
}
return q;
}
public static int getCount (int[]a, int p, int r)
{
int i = p;
int j = p+1;
int count = 0;
while (i<r && j<r)
{
if(a[i]<=a[j])
count++;
i++;
j++;
}
return count;
}
public static int getLongestSubsequence (int[] a, int p, int r) {
int count = 0;
if (p<r)
{
int q = getPartition (a, p, r);
count = getCount(a,p,r);
if (count < getLongestSubsequence(a,p,q))
count = getLongestSubsequence(a, p, q);
else if (count < getLongestSubsequence(a, q+1, p))
{
count = getLongestSubsequence(a, q+1, p);
}
}
return count;
}
public static int LongestSubsequence (int[] a) {
return getLongestSubsequence(a, 0, a.length);
}
public static void main(String[] args) {
int[] a = {1,3,5,9,2, 1, 3};
System.out.println(LongestSubsequence(a));
}
}
This is a pretty big body of code, and it's a little hard to follow with all the a's, r's, q's, etc.
In general, I would create an array (call it longestSeq) where longestSeq[i] is the length of the longest non-decreasing sequence found so far that starts at index, i, of your original sequence. For instance, if I had
int[] sequence = new int[] { 3, 5, 1, 2 }
then the algorithm would yield
longestSeq[0] = 2;
longestSeq[1] = 1;
longestSeq[2] = 2;
longestSeq[3] = 1;
So you would initialize longestSeq to all 0's, and then iterate through your list and fill in these values. At the end, just take the max of longestSeq.
Maybe start with just trying to make it work iteratively (without recursion) and then add recursion if that's a requirement.

Categories

Resources