I am trying to write a 3 input recursive program for max and min for a data structures class. I am getting a stack overflow error. I cannot tell if I am going off the end of the array, but I shouldn't be as far as my understanding goes. Any help would be appreciated. Here is my code:
class Extrema {
// maxArray()
// returns the largest value in int array A
// p is position zero, r is position length-1
static int maxArray(int[] A, int p, int r) {
int q;
if (p == r) {
return A[p];
} else {
q = (p + r)/2;
return max(maxArray(A, p, q-1), maxArray(A, q+1, r));
}
}
// max()
// returns the largest value of two ints
private static int max(int a, int b) {
return a > b ? a : b;
}
// main()
public static void main(String[] args) {
int[] B = {-1, 2, 6, 3, 9, 2, -3, -2, 11, 5, 7};
System.out.println( "max = " + maxArray(B, 0, B.length-1) ); // output: max = 11
}
}
Either do it non recursive since recursion really does not make any sense here:
static int maxArray(int[] A, int p, int r) {
int max = A[p];
for (int i = p + 1; i <= r; i++) {
if (A[i] > max)
max = A[i];
}
return max;
}
Or if you insist on some kind of recursion use your code existing with just a minor change:
return max(maxArray(A, p, q), maxArray(A, q+1, r));
Note the call to the first maxArray function now gets passed q and not q-1 as end index.
Change this code
if (p == r) {
return A[p];
}
to
if (p >= r) {
return A[p];
}
and note that when you call statement
return max(maxArray(A, p, q-1), maxArray(A, q+1, r));
you lose q element, so call
return max(maxArray(A, p, q), maxArray(A, q+1, r));
Related
I am trying to find out the index of the smallest number in an int array using divide and conquer and I have this stack overflow error:
Exception in thread "main" java.lang.StackOverflowError
at java.lang.StrictMath.floor(Unknown Source)
at java.lang.Math.floor(Unknown Source)
This is my divide and conquer method:
private static int dC(int[] a, int f, int l) {
if(f == 1)
return f;
if(a[dC(a, f, (int)(Math.floor((double)(f+l)/2)))] > a[dC(a, (int)(Math.floor((double)(f+l)/2)+1), l)])
return dC(a, (int)(Math.floor((double)(f+l)/2)+1), l);
else
return dC(a, f, (int)(Math.floor((double)(f+l)/2)));
}
Here is what I put in my main method:
int[] a = {35,30,40,50};
System.out.println(dC(a, 0, 3));
You have a problem with your stoping "rule"
private static int dC(int[] a, int f, int l) {
if(l == f) // <-- This mean you have one item, so you want to return it.
return f;
if(a[dC(a, f, (int)(Math.floor((double)(f+l)/2)))] > a[dC(a, (int)(Math.floor((double)(f+l)/2)+1), l)])
return dC(a, (int)(Math.floor((double)(f+l)/2)+1), l);
else
return dC(a, f, (int)(Math.floor((double)(f+l)/2)));
}
Also, I would try to do the calculation only once, so something like this (also what Joop Eggen said about Integers arithmetics):
private static int dC(int[] a, int f, int l) {
if(l == f)
return f;
int m = (f+l) / 2;
int left = dC(a, f, m);
int right = dC(a, m+1, l);
if(a[left] > a[right])
return left;
else
return right;
}
This is just the classical binary search problem. From what I can glean by looking at your code, you seem to be getting bogged down in the logic used to make each recursive call to the left and right subarrays of the current array. The logic I used below is to take everything from the start to (start+end)/2 for the left recursion, and everything from ((start+end)/2) + 1 to end for the right recursion. This guarantees that there would never be any overlap.
The base case occurs when the algorithm finds itself sitting on a single entry in the array. In this case, we just return that value, and we do not recurse further.
private static int dC(int[] a, int start, int end) {
if (start == end) return a[start];
int left = dC(a, start, (start+end)/2);
int right = dC(a, ((start+end)/2) + 1, end);
return left < right ? left : right;
}
public static void main(String args[])
{
int[] a = {10, 3, 74, 0, 99, 9, 13};
System.out.println(dC(a, 0, 6)); // prints 0
}
Demo
Note: I have no idea what role Math.floor would be playing here, since you're using arrays of integer numbers, not doubles or floats. I removed this, because I saw no need for it.
It's a typical problem locating the index to the min/max, you can try it as:
public static void main(String... args) {
int[] arr = generateArrays(100, 1000, 0, 10000, true);
int minIndex = findMinIndex(arr, 1, arr.length - 1);
int theMin = arr[minIndex];
Arrays.sort(arr);
System.out.println(String.format("The min located correctly: %s", arr[0] == theMin));
}
private static int findMinIndex(int[] a, int l, int r) {
if (r - l < 1) return l;
int mid = l + (r - l) / 2;
int lIndex = findMinIndex(a, l + 1, mid);
int rIndex = findMinIndex(a, mid + 1, r);
int theMinIndex = l;
if (a[lIndex] < a[theMinIndex]) theMinIndex = lIndex;
if (a[rIndex] < a[theMinIndex]) theMinIndex = rIndex;
return theMinIndex;
}
And the helper to generate a random array.
public static int[] generateArrays(int minSize, int maxSize, int low, int high, boolean isUnique) {
Random random = new Random(System.currentTimeMillis());
int N = random.nextInt(maxSize - minSize + 1) + minSize;
if (isUnique) {
Set<Integer> intSet = new HashSet<>();
while (intSet.size() < N) {
intSet.add(random.nextInt(high - low) + low);
}
return intSet.stream().mapToInt(Integer::intValue).toArray();
} else {
int[] arr = new int[N];
for (int i = 0; i < N; ++i) {
arr[i] = random.nextInt(high - low) + low;
}
return arr;
}
}
Given a sequence of integers, how can I find the average of it using a divide and conquer approach? I have to write a method "double avg(int[] a, int l, int r)" that finds the average in the array A, spanning from 'l' to 'r' as homework, but I get a StackOverflowError on the first recursive call - not in the second, though! - of my code, and I can't seem to understand why. Also, I'm pretty sure it doesn't give me a true average, but I found no way to check the average of a sequence using the divide and conquer. Here is my code:
public class Average {
public static void main(String[] args) {
int[] A = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int l = 0;
int r = A.length-1;
System.out.println("Average of the array: "+averageCheck(A, l, r));
}
public static double averageCheck(int[] A, int l, int r) {
if (l==r) {
return A[l];
}
// Base Case: if there's just a single element it is the average of the array itself
int mid = (l+r)/2;
double avLeft = 0;
double avRight = 0;
avLeft = A[l]/r + averageCheck(A, l, mid);
avRight = A[mid+1]/r + averageCheck(A, mid+2, r);
double average = ( (avLeft*mid) + (avRight * (r-mid) ) ) /r;
return average;
}
}
Your recursivity does not end when r == l + 1. In this case, mid == l and in the second recursive call, mid+2 will be greater than r. Add this at the beginning of the function:
if(l > r)
return 0;
Example, imagine l == 5 and r == 6, then mid will have the value 5. The second call will be averageCheck(A, 7, 6) as mid+2 is 7. In this call, the condition l == r will be false. Continue in the same logic and you will find that the recursivity will not end.
I think also that it would be better if you calculate the sum recursively and divide by the length at the end.
I suggest this solution:
public class Average {
public static void main(String[] args) {
int[] A = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
System.out.println("Average of the array: "+average(A));
}
public static double average (int[] A) {
return averageCheck(A, 0, A.length - 1) / A.length;
}
public static double averageCheck(int[] A, int l, int r) {
if (l > r)
return 0;
if (l==r) {
return A[l];
}
// Base Case: if there's just a single element it is the average of the array itself
int mid = (l+r)/2;
double avLeft = 0;
double avRight = 0;
avLeft = averageCheck(A, l, mid);
avRight = averageCheck(A, mid+1, r);
double average = avLeft + avRight;
return average;
}
}
I am writing a specific variant of quicksort class. However; the directions on this variant of quick sort is confusing me. I have written the code for quick sort, but I do not understand the description. Can anyone help me understand this description means for the variant so I can finalize it?
Description: implement a variant of quicksort with pivots chosen according to pivot_pos. That is, whenever the quicksort makes a recursive call to quicksort a subarray (A, p, r), it chooses as the pivot min(p+pivot,r).
To my interpretation, this is saying to include within the if statement of quicksort a int value of min(p + pivot, r). It would partition the array with the pivot representing this value, and quicksorting the array with this value as well.
public static int partition(int[] a, int p, int r)
{
int x = a[r];
int i = p - 1;
for( int j = p; j <= r - 1; j++)
{
if(a[j] <= x)
{
i++;
swap(a, i, j);
}
}
swap(a, i + 1, r);
return i + 1;
}
public static void quick_sort(int[] a, int p, int r)
{
if(p < r)
{
int q = partition(a, p, r);
quick_sort(a, p, q - 1);
quick_sort(a, q + 1, r);
}
}
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.
So I've been trying to implement a quicksort myself, but it generates a stackoverflowerror, but I can't seem to find what the cause is.
Can someone help me?
public static int partition(int[] a, int p, int q){
int i = 0;
for (int j = p; j < q; ++j){
if(a[j] <= a[q]){
int tmp = a[j];
a[j] = a[i];
a[i] = tmp;
i++;
}
}
int tmp = a[i];
a[i] = a[q];
a[q] = tmp;
return i;
}
public static void qsort(int[] a, int p, int q){
if(p < q){
int x = partition(a, p, q);
qsort(a, p, x - 1);
qsort(a, x + 1, q);
}
}
public static void main(String args[]){
int[] a = {4, 6, 2, 9, 8, 23, 0, 7};
qsort(a, 0, a.length - 1);
for(int i : a){
System.out.print(i + " ");
}
}
There are several bugs, but the immediate one you're hitting is that in partition(), i is not constrained to be between p and q. You pretty quickly end up in a situation where p=2, q=3 yet the final value of i is 1. This results in infinite recursion as qsort() keeps calling itself with identical arguments.
A stack overflow error means the stop condition for the recursion is never reached, in this case p < q is never true. Use a debugger, set a breakpoint for that line, and look for when qsort() is repeatedly recursively called with the same parameters.