How do we check if an array represents a heap data structure recursively?
Assume it is an array of integers, and I am checking for max heap.
The following is what I came up with, but I don't know if that is correct.
public static boolean isHeap(int[] arr) {
if (arr = null)
return false;
return isHeapTree(arr, 0);
}
private static boolean isHeapTree(int[] arr, int i) {
if (i = arr.length - 1)
return true;
// check if a parent's value is larger or equal to both of
// its left child and right child
else if (arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2])
return (isHeapTree(arr, 2i + 1) && isHeapTree(arr, 2i + 2));
else
return false;
}
is it possible a binary heap could be incomplete? say:
100
/ \
50 20
/ \ \
30 40 26
Some comments:
You definitely don't need the while loop - you always return after the first iteration
2i + 1 doesn't work in java, you need to use 2*i + 1
arr[2*i + 1] and arr[2*i + 1] may throw and ArrayIndexOutOfBoundsException so you need to either manually do a range check, or wrap it in a try.. catch block
Typically, when a heap is stored in an array, it is always packed to the left. In other words, when the heap has n elements, the all elements in the array in the index range [0, n-1] contain elements. Every insert starts by placing the element at index size(), and then it jumps up until it is smaller than its parent.
So the approach you are taking can succeed.
Also note that in your code, you can deal with going out of bounds with a small change to your guard on top:
public static boolean isHeap(int[] arr, int size) {
return (null == arr) ? false : isHeapTree(arr, size, 0);
}
private static boolean isHeapTree(int[] arr, int size, int i) {
assert i >= 0;
assert size <= arr.length;
if (i >= size) return true;
...
Related
I was given an assignment and we are only allowed to use recursive methods to solve different problems given to us.
I'm fairly new to programming and I'm having a hard time wrapping my head around it.
One of the objectives in the assignment is to calculate the max value of all possible paths in any given 2D integer array. Basically what this means is that when given a 2D int array, I need to use recursion to go through all different paths (abiding to the rules of only moving one element down or one element to the right at a time) in the array and return the value of the path with the highest sum value of elements in that path.
For example: (just a random example, could be any 2D int array with no particular order or size)
int[][] arr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}};
the output should be: '48' (1 + 5 + 9 + 10 + 11 + 12)
This is what I have so far (but I have a feeling I'm way off):
public static int maxVal(int[][] arr) {
return maxVal(arr, 0, 0);
} // end of method
// Returns the value of the maximal path in the
// given 2D array, starting at location (i,j)
private static int maxVal(int[][] arr, int i, int j) {
// terminates when reaches last element
if ((i + 1) == arr.length && (j + 1) == arr[0].length) {
return 0;
} else {
// if the elemnt is at the last column
if ((i + 1) == arr.length) {
return maxVal(arr, i, j) + arr[i][j - 1];
// if element is at the last row
} else if ((j + 1) == arr[0].length) {
return maxVal(arr, i, j) + arr[i - 1][j];
} else {
return maxVal(arr, i, j) + arr[i - 1][j - 1];
}
}
}
I keep getting a StackOverFlowError. Any suggestions would be very helpful.
If you look closely, you will see that you are calling the same method over and over again return maxVal(arr, i, j), this will cause the SOF exception because there will be infi recursion calls since nothing is changing that will trigger the base cases.
You should instead return the current value added to the max value of the right/bottom.
private static int maxVal(int[][] arr, int i, int j)
{
if (i >= arr.length || i < 0 || j >= arr[i].length || j < 0) return 0;
int right = maxVal(arr, i, j + 1);
int bottom = maxVal(arr, i + 1, j);
return arr[i][j] + Math.max(right, bottom);
}
Try not to get lost in the recursion rabbit hole, instead set the correct base case which is once you reach an invalid i or j, you should just return 0 (end of current path)
if (i >= arr.length || i < 0 || j >= arr[i].length || j < 0) return 0;
if both indicies are valid, you will then have to recursively calculate the right and bottom values until it eventually reaches the end of the path (invalid indicies)
After that's done you will have two values, that are the result of the max sum of possible paths from your current right and current bottom, then you add your current value to the max value (right/bottom) and return it.
I'm trying to find the average of all even numbers in an array using recursion and I'm stuck.
I realize that n will have to be decremented for each odd number so I divide by the correct value, but I can't wrap my mind around how to do so with recursion.
I don't understand how to keep track of n as I go, considering it will just revert when I return.
Is there a way I'm missing to keep track of n, or am I looking at this the wrong way entirely?
EDIT: I should have specified, I need to use recursion specifically. It's an assignment.
public static int getEvenAverage(int[] A, int i, int n)
{
// first element
if (i == 0)
if (A[i] % 2 == 0)
return A[0];
else
return 0;
// last element
if (i == n - 1)
{
if (A[i] % 2 == 0)
return (A[i] + getEvenAverage(A, i - 1, n)) / n;
else
return (0 + getEvenAverage(A, i - 1, n)) / n;
}
if (A[i] % 2 == 0)
return A[i] + getEvenAverage(A, i - 1, n);
else
return 0 + getEvenAverage(A, i - 1, n);
}
In order to keep track of the number of even numbers you have encountered so far, just pass an extra parameter.
Moreover, you can also pass an extra parameter for the sum of even numbers and when you hit the base case you can return the average, that is, sum of even numbers divided by their count.
One more thing, your code has two base cases for the first as well as last element which is unneeded.
You can either go decrementing n ( start from size of array and go till the first element ), or
You can go incrementing i starting from 0 till you reach size of array, that is, n.
Here, is something I tried.
public static int getEvenAvg(int[] a, int n, int ct, int sum) {
if (n == -1) {
//make sure you handle the case
//when count of even numbers is zero
//otherwise you'll get Runtime Error.
return sum/ct;
}
if (a[n]%2 == 0) {
ct++;
sum+=a[n];
}
return getEvenAvg(a, n - 1, ct, sum);
}
You can call the function like this getEvenAvg(a, size_of_array - 1, 0, 0);
Example
When dealing with recursive operations, it's often useful to start with the terminating conditions. So what are our terminating conditions here?
There are no more elements to process:
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
... okay, now how do we reduce the number of elements to process? We should probably increment index?
index++;
... oh, but only when going to the next level:
getEvenAverage(elements, index++, sum, count);
Well, we're also going to have to add to sum and count, right?
sum += a[index];
count++;
.... except, only if the element is even:
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
... and that's about it:
static int getEvenAverage(int[] elements, int index, int sum, int count) {
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
return getEvenAverage(elements, index + 1, sum, count);
}
... although you likely want a wrapper function to make calling it prettier:
static int getEvenAverage(int[] elements) {
return getEvenAverage(elements, 0, 0, 0);
}
Java is not a good language for this kind of thing but here we go:
public class EvenAverageCalculation {
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6,7,8,9,10};
System.out.println(getEvenAverage(array));
}
public static double getEvenAverage(int[] values) {
return getEvenAverage(values, 0, 0);
}
private static double getEvenAverage(int[] values, double currentAverage, int nrEvenValues) {
if (values.length == 0) {
return currentAverage;
}
int head = values[0];
int[] tail = new int[values.length - 1];
System.arraycopy(values, 1, tail, 0, tail.length);
if (head % 2 != 0) {
return getEvenAverage(tail, currentAverage, nrEvenValues);
}
double newAverage = currentAverage * nrEvenValues + head;
nrEvenValues++;
newAverage = newAverage / nrEvenValues;
return getEvenAverage(tail, newAverage, nrEvenValues);
}
}
You pass the current average and the number of even elements so far to each the recursive call. The new average is calculated by multiplying the average again with the number of elements so far, add the new single value and divide it by the new number of elements before passing it to the next recursive call.
The way of recreating new arrays for each recursive call is the part that is not that good with Java. There are other languages that have syntax for splitting head and tail of an array which comes with a much smaller memory footprint as well (each recursive call leads to the creation of a new int-array with n-1 elements). But the way I implemented that is the classical way of functional programming (at least how I learned it in 1994 when I had similar assignments with the programming language Gofer ;-)
Explanation
The difficulties here are that you need to memorize two values:
the amount of even numbers and
the total value accumulated by the even numbers.
And you need to return a final value for an average.
This means that you need to memorize three values at once while only being able to return one element.
Outline
For a clean design you need some kind of container that holds those intermediate results, for example a class like this:
public class Results {
public int totalValueOfEvens;
public int amountOfEvens;
public double getAverage() {
return totalValueOfEvens + 0.0 / amountOfEvens;
}
}
Of course you could also use something like an int[] with two entries.
After that the recursion is very simple. You just need to recursively traverse the array, like:
public void method(int[] values, int index) {
// Abort if last element
if (index == values.length - 1) {
return;
}
method(array, index + 1);
}
And while doing so, update the container with the current values.
Collecting backwards
When collecting backwards you need to store all information in the return value.
As you have multiple things to remember, you should use a container as return type (Results or a 2-entry int[]). Then simply traverse to the end, collect and return.
Here is how it could look like:
public static Results getEvenAverage(int[] values, int curIndex) {
// Traverse to the end
if (curIndex != values.length - 1) {
results = getEvenAverage(values, curIndex + 1);
}
// Update container
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
// Return accumulated results
return results;
}
Collecting forwards
The advantage of this method is that the caller does not need to call results.getAverage() by himself. You store the information in the parameters and thus be able to freely choose the return type.
We get our current value and update the container. Then we call the next element and pass him the current container.
After the last element was called, the information saved in the container is final. We now simply need to end the recursion and return to the first element. When again visiting the first element, it will compute the final output based on the information in the container and return.
public static double getEvenAverage(int[] values, int curIndex, Results results) {
// First element in recursion
if (curIndex == 0) {
// Setup the result container
results = new Results();
}
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
int returnValue = 0;
// Not the last element in recursion
if (curIndex != values.length - 1) {
getEvenAverage(values, curIndex + 1, results);
}
// Return current intermediate average,
// which is the correct result if current element
// is the first of the recursion
return results.getAverage();
}
Usage by end-user
The backward method is used like:
Results results = getEvenAverage(values, 0);
double average results.getAverage();
Whereas the forward method is used like:
double average = getEvenAverage(values, 0, null);
Of course you can hide that from the user using a helper method:
public double computeEvenAverageBackward(int[] values) {
return getEvenAverage(values, 0).getAverage();
}
public double computeEvenAverageForward(int[] values) {
return getEvenAverage(values, 0, null);
}
Then, for the end-user, it is just this call:
double average = computeEvenAverageBackward(values);
Here's another variant, which uses a (moderately) well known recurrence relationship for averages:
avg0 = 0
avgn = avgn-1 + (xn - avgn-1) / n
where avgn refers to the average of n observations, and xn is the nth observation.
This leads to:
/*
* a is the array of values to process
* i is the current index under consideration
* n is a counter which is incremented only if the current value gets used
* avg is the running average
*/
private static double getEvenAverage(int[] a, int i, int n, double avg) {
if (i >= a.length) {
return avg;
}
if (a[i] % 2 == 0) { // only do updates for even values
avg += (a[i] - avg) / n; // calculate delta and update the average
n += 1;
}
return getEvenAverage(a, i + 1, n, avg);
}
which can be invoked using the following front-end method to protect users from needing to know about the parameter initialization:
public static double getEvenAverage(int[] a) {
return getEvenAverage(a, 0, 1, 0.0);
}
And now for a completely different approach.
This one draws on the fact that if you have two averages, avg1 based on n1 observations and avg2 based on n2 observations, you can combine them to produce a pooled average:
avgpooled = (n1 * avg1 + n2 * avg2) / (n1 + n2).
The only issue here is that the recursive function should return two values, the average and the number of observations on which that average is based. In many other languages, that's not a problem. In Java, it requires some hackery in the form of a trivial, albeit slightly annoying, helper class:
// private helper class because Java doesn't allow multiple returns
private static class Pair {
public double avg;
public int n;
public Pair(double avg, int n) {
super();
this.avg = avg;
this.n = n;
}
}
Applying a divide and conquer strategy yields the following recursion:
private static Pair getEvenAverage(int[] a, int first, int last) {
if (first == last) {
if (a[first] % 2 == 0) {
return new Pair(a[first], 1);
}
} else {
int mid = (first + last) / 2;
Pair p1 = getEvenAverage(a, first, mid);
Pair p2 = getEvenAverage(a, mid + 1, last);
int total = p1.n + p2.n;
if (total > 0) {
return new Pair((p1.n * p1.avg + p2.n * p2.avg) / total, total);
}
}
return new Pair(0.0, 0);
}
We can deal with empty arrays, protect the end-user from having to know about the book-keeping arguments, and return just the average by using the following public front-end:
public static double getEvenAverage(int[] a) {
return a.length > 0 ? getEvenAverage(a, 0, a.length - 1).avg : 0.0;
}
This solution has the benefit of O(log n) stack growth for an array of n items, versus O(n) for the various other solutions that have been proposed. As a result, it can deal with much larger arrays without fear of a stack overflow.
I need to write a code that will shift elements to the right for k places, and the element is index position. Also I should suppose that my array List is linked in circle.
Example:
list = [1,2,3,4];
list.shiftRight(1,2);
list = [1,3,4,2]
For the circle list I think of:
list = [1,2,3,4];
list.shiftRight(2, 3);
list = [1,3,2,4].
This is my code but it's not working properly.
public void shiftRight(int index, int k) throws ArrayIndexOutOfBoundsException{
if (index < 0 || index > this.list.size())
throw new ArrayIndexOutOfBoundsException();
if (k + index > this.list.size()) {
int element = this.list.remove(index);
this.list.add(this.list.size() - k, element);
} else {
int element = this.list.remove(index);
this.list.add(k + index , element);
}
//System.out.println("ShiftedRight " + this.list);
}
Also here is the code for shifting elements to the left which also doesn't work. ^_^
public void shiftLeft(int index, int k) throws ArrayIndexOutOfBoundsException {
if (index < 0 || index > this.list.size())
throw new ArrayIndexOutOfBoundsException();
if (k + index > this.list.size()) {
int element = this.list.remove(index);
this.list.add(this.list.size() - k + index, element);
} else {
int element = this.list.remove(index);
this.list.add(index - k, element);
}
//System.out.println("ShiftedLeft " + this.list);
}
You're on the right track. There are a few edge conditions to consider. And you have to be very careful with indexes, lengths and being off by one.
Firstly, note that in a list of 4 elements, the valid indexes are [0..3]. That is, the maximum index is one less than the length.
Secondly, k appears to be unbounded. I assume it's meant to be non-negative. If so, you should check for this. It can be many times larger than the length of the list, ie. you can loop around more than once. So we use modulo arithmetic.
Thirdly, when you remove an element from the list the indexes change. You need to handle this when adding the element back in.
public void shiftRight(int index, int k)
throws ArrayIndexOutOfBoundsException
{
int length = this.list.size();
// Note: index cannot be equal to length. You were testing for >.
if ((index < 0) || (index >= length))
{
throw new ArrayIndexOutOfBoundsException('out of range index: ' + index);
}
int shift = k % length; // Use modulo arithmetic to determine a shift in the range [0..length).
if (shift == 0)
{
return; // No change, we're done.
}
int newIndex = (index + shift) % length; // Calculate where to move to, again using modulo arithmetic, to get the loop around.
int element = this.list.remove(index);
this.list.add(newIndex, element);
}
I've only hand-tested this so let me know if there are any issues. shiftLeft() should be similar, although watch out for negative numbers in modulo arithmetic.
My algorithm is suppose to tell me if 'x'(which has the value 5) is in the sorted array. However, I keep getting a 0. Well since my condition states that if 'x' is not in the array show 0. Where am I going wrong?
import java.util.Arrays;
public class binarySeacg {
public static void main (String[]args)
{
int[] array = {10,7,11,5,13,8};
exchangesort(array);
binsearch(array,5);
System.out.println(Arrays.toString(array));
}
public static void exchangesort(int[] S)
{
int i,j,temp;
for(i=0;i<S.length;i++)
for(j=i+1;j<S.length;j++)
if(S[i]>S[j])
{
temp = S[i];
S[i] = S[j];
S[j] = temp;
}
}
public static int binsearch(int[] S, int x)
{
int location, low, high, mid;
low = 1; high = S.length;
location = 0;
while(low<=high && location==0)
{
mid =(low + high)/2;
if(x== S[mid])
location = mid;
else if(x < S[mid])
high = mid -1;
else
low = mid + 1;
}
System.out.println(location);
return location;
}
}
You set low = 1;, and 5 is the minimal element - so it is in index 0 - so in the sublist of [1,S.length] - it is indeed not there.
You should set low = 0;, and start from the first element - not the second. (Remember that index in java starts from 0, not 1).
(PS, note that in this specific case - the algorithm is correct, since in the sorted list - 5 is in the index 0).
Here you are sorting an array and then the sorted array is used for searching the element.
And if the search is successful, then you do the below assignment
location = mid; which means you are assigning the matching element's index to the location variable.
In this case, element 5 is in 0th index.
Hence you are always getting 0 on your STDOUT
Because, you are trying to find x value, which you are passing 3 and in your list. It is not present. So, change it to other value like 5 and then try.
Also, you should start low=0 instead of low=1. Because, it will miss the first element all the time.
public static int binsearch(int[] S, int x)
{
int location, low, high, mid;
low = 0; high = S.length;
location = 0;
while(low<=high && location==0)
{
mid =(low + high)/2;
if(x == S[mid])
{
location = mid;break;
}
else if (x < S[mid])
{
high = mid - 1;
} else
{
low = mid + 1;
}
}
System.out.println(location);
return location;
}
Note : For the different output, change the value binsearch(array,5); here, which is called from main() method. Remember, change the value, which are present in your list.
in java and most languages, the index starts from 0, not 1, and ends at n-1, not n
for binary search, check carefully about when exiting the while loop, and always remember the meaning of your low and high variables, whether it is [low, high], or [low, high)
for this specific problem, u should also consider what if there r duplicates in the array. whether to return the first element or anyone in the array
assume that i have an array int [] arr={1,2,4,5,7} and also have number 6
so i need the result to be 01100 that means that 2+4=6 in the array so the result will be 1 if the number in the sum 0 otherwise
also i need number of bits in the result be the same number as array lenght
i need java method that perform this operation
This is very similar to the subset sum problem, i.e., given a set of integers, determine if a non-empty subset equals zero. In your case, you need to determine if a non-empty subset equals a specific integer. The latter part about filling in the bit array is purely cosmetics.
A simple way to solve it -- albeit not very efficient, i.e., O(2^N*N) -- is to cycle between every possible subset of integers in your array (power set), and determine if the sum of this subset equals the number you are given.
Here is a way to do it recursively. As noted by JG, there is no efficient solution for the general problem.
private static int[] solve(int[] arr, int target, int res[], int length, int sum) {
if (length == arr.length)
return (sum == target)? res : null;
res[length] = 0;
int[] r = solve(arr, target, res, length + 1, sum);
if (r != null)
return r;
res[length] = 1;
r = solve(arr, target, res, length + 1, sum + arr[length]);
if (r != null)
return r;
return null;
}
public static int[] solve(int[] arr, int target) {
return solve(arr, target, new int[arr.length], 0, 0);
}