Implementing an equals method recursively - java

Basically, I need to compare two arrays and check if they have the same values in the same positions (recursively of course). I get an error with my current code: Array out of index exception:20
The code I have right now looks as follows:
private boolean equalsHelper(int[] first, int[] second, int iStart, int iEnd){
if (first[iStart] == second[iStart]){
if (equalsHelper(first,second,(iStart+1),iEnd))
{
return true;
}
}
if (iStart == iEnd){
return first[iEnd] == second[iEnd];
}
return false;
}

You simply need to put you stop condition at the begin of you code. This will work if iStart is 0 at the beginning and iEnd is array length - 1.
private boolean equalsHelper(int[] first, int[] second, int iStart, int iEnd) {
if (iStart == iEnd) { // you need to check this first
return first[iEnd] == second[iEnd];
}
if (first[iStart] == second[iStart]) {
if (equalsHelper(first, second, (iStart + 1), iEnd)) {
return true;
}
}
return false;
}
If you want to use the array length as input for iEnd you just need to change the code a little
private boolean equalsHelper2(int[] first, int[] second, int iStart, int iEnd) {
if (iStart == iEnd) {
return true;
}
if (first[iStart] == second[iStart]) {
if (equalsHelper2(first, second, (iStart + 1), iEnd)) {
return true;
}
}
return false;
}
Since performance was mentioned a few times I will say a few things about it.
The stack contains information about local variables and function calls. So each recursiv call will save these informations on the stack which will lead to a stackoverflow on huge inputs since the stack only has limited space. It is also slower in terms of execution due to more assembler commands in comparison to loops.
This can be avoided by using tail recursive functions.
A tail recursive call means simply that your recursive call must be the last statement that is executed in your method. The compiler will translate this into a loop. This is faster and uses less space on the stack.
A tail recursive version of your equals method would look like this:
private boolean equalsHelper2(int[] first, int[] second, int iStart, int iEnd)
{
if (iStart == iEnd)
{
return true;
}else{
if(first[iStart] != second[iStart])
{
return false;
} else
{
return equalsHelper2(first, second, iStart + 1, iEnd);
}
}
}

Leaving aside the question of whether recursion is the right solution (it really isn't, iteration here is trivial and will perform better), the problem is that the termination condition (iStart == iEnd) is not checked until after the recursive call.
Any recursive algorithm must a) check whether it is appropriate to continue recursing, and b) do the recursive call after that check. Failing to include the first step, or doing the steps out of order, will result in infinite recursion until an error is reached (StackOverflowError if nothing else happens first).
You do have a condition check before your recursive call, but it's for the method's overall purpose rather than for ending recursion. You also have a condition check for ending recursion, but it's done after the recursive call. The solution is to swap their order - take the if (iStart == iEnd) block and move it to before the if (first[iStart] == second[iStart]) block.

Recursion is a powerful programming technique, but has some draw backs in the Java language. If a method in java calls itself recursively an excessive number of times before returning it will lead to a StackOverflowError. It this instance, comparing equality of two Array's is almost guaranteed to do so.
Other languages like Scala allow you to write recursive functions which are optimised for recursion (tail recursive) and execute in constant stack space.
That been said, you should think whether recursion is really the correct solution here. It neither optimises the solution, nor adds code clarity.
Note: If you just want to compare two Array's in Java, then java.util.Arrays already has you covered.

Related

Recursive function that returns a count of elements with the specified value in a linked list

I am working on a function, countH(), that is supposed to count the amount of times a given number appears in a linked list. For some reason, I cannot get this to work recursively. I have tried a number of different solutions but I guess I can't get something in the correct place. Sorry if I am asking the question poorly, I struggle to understand recursion formatting sometimes.
Here is the function:
public int count(int i) {
return countH(first, i);
}
private int countH(Node front, int i) { // TODO
int cter = 0;
if (front.next==null) {
return 0;
}
if(front.item == i)
cter++;
return countH(front, cter);
}
This is a late version of my code, I'm sure it was a bit better before I messed with it a bunch to try to get it to work
Thanks!
Every recursive implementation consists of two parts:
base case - that represents a simple edge-case for which the outcome is known in advance. For this task, the base case is a situation the given Node is null. Think about it this way: if a head-node is not initialed it will be null and that is the simplest edge-case that your method must be able to handle. And return value for the base case is 0.
recursive case - a part of a solution where recursive calls a made and where the main logic resides. In the recursive case, you need to check the value of a current node. If it matches the target value, then the result returned by the method will be 1 + countH(cur.next, i), otherwise it will be a result of the subsequent recursive call countH(cur.next, i).
Base case is always placed at the beginning of the method, followed by a recursive case.
And when you are writing a recursive part, one of the most important things that you have to keep in mind is which parameters change from one recursive call to another, and which remains the same. In this case, changes only a Node, the target value i remains the same.
public int count(int i) {
return countH(first, i);
}
private int countH(Node cur, int i) { // `front` replaced by `cur`
if (cur == null) { // not cur.next == null (it'll fail with exception if the head-node is null)
return 0;
}
// int cter = 0; // this intermediate variable isn't needed, it could be incremted by 1 at most during the method execution
// if(cur.item == i)
// cter++;
// return countH(cur, cter); // this line contains a mistake - variable `i` has to be passed as a parameter and `cter` must be added to the result returned by a recursive call
return cur.item == i ? 1 + countH(cur.next, i) : countH(cur.next, i);
}
Suggestion
Follow the comments in the code. I've left your original lines in place so that will be easier to compare solutions. Also, always try to come up will reasonable self-explanatory names for variables (as well as methods, classes, etc). For that reason, I renamed the parameter front to cur (short for current), because it's meant to represent any node, not first or any other particular node.
Side note
This statement is called a ternary operator or inline if statement
cur.item == i ? 1 + countH(cur.next, i) : countH(cur.next, i);
And it's just a shorter syntax for the code below:
if (cur.item == i) {
return 1 + countH(cur.next, i);
} else {
return countH(cur.next, i);
}
You could use either of these constructs in your code. The difference is only in syntax, both will get executed in precisely the same way.
In a linked list, you should have one element and from that you get the value and the next element. So your item could look like (I am omitting getters, setters and exception handling):
class Item {
Object value;
Item next;
}
Then your counter for a specific value could look like
int count(Object valueToCount, Item list) {
int result = 0;
if (valueToCount.equals(list.value)) {
result++; // count this value
}
if (value.next != null) {
result += count(valueToCount, value.next) // add the count from remainder of the list
}
return result;
}
public int count(int i) {
return countH(first, i);
}
private int countH(Node front, int i) { // TODO
if(front==null) {
return 0;
}
if (front.item == i) {
return 1 + countH(front.next, i);
} else {
return countH(front.next, i);
}
}

Recursive Statement not Instantly Returning

I am creating a method that takes a list of numbers and an index.
If there is a number after the index that is six times the first number, it returns true. Otherwise, it returns false.
public static boolean firstElementMultiple(int []Numbers, int index) {
System.out.println(Numbers[index]);
if ((Numbers[0]*6)==Numbers[index]){
System.out.println("Yep");
return true;
}
if (index+1 >= Numbers.length){
return false;
}
firstElementMultiple(Numbers, index+1);
return false;
With a list of {5,6,7,30} and an index of 1, false is returned, even though 30 is in the list.
6
7
30
Yep
Is printed, which shows me that it did recognise that 30 was in the list. However, it is still returning false even though the next statement is true and should stop the method?
This has to be done by recursion.
edit: I have to put the 'return false;' at the end as, without it, it doesn't let me. However, I don't see how it can ever get there because there is always a recursive call in the way.
firstElementMultiple(Numbers, index+1);
return false;
Here's the end of your method. This is what it does. It says "Call firstElementMultiple to keep looking for the value we're looking for. Once you've finished looking, completely ignore whether or not you found it and return false anyway."
Given that, how can you fix it to do what you want it to do, namely return whether or not we found the element?
Because in the end, you are returning false in your recursive function no matter what you get in further calculations. You should change your code to this:
public static boolean firstElementMultiple(int []Numbers, int index) {
System.out.println(Numbers[index]);
if ((Numbers[0]*6)==Numbers[index]){
System.out.println("Yep");
return true;
}
if (index+1 >= Numbers.length){
return false;
}
return firstElementMultiple(Numbers, index+1);
}
Basically you need to change
firstElementMultiple(Numbers, index+1);
return false;
to
return firstElementMultiple(Numbers, index+1);

why does my java program not iterate?

This is supposed to check if an int occurs at a specific index in an array or at any other index over that. However, my for loop doesn't loop
public static boolean searchIterative(int[] list, int f, int x){
for (; f<list.length;f++){
return list[f]==x;
}
return false;
}
You return immediately after entering your loop. return exits the loop (and the function.
Regardless of whether or not the value is true, the first time you enter the loop you return a true or false - you return the conditional statement list[f]==x;
You want to iterate through until you find it, and then return true, or return false if you never find it. If you need to find if it's in multiple places you need to count each time you find it within the method, and then return that.

Comparing one ArrayList to another ArrayList using boolean method in java

I am trying to get a boolean method to return true or false on wether two arrayLists are equal to each other. The arraysLists are array and array1. The user inputs them. Right now here is the code that I thought would work:
public boolean equals(){
//if both are equal return true, else false
boolean test = false;
for(int i = 0; i < array1.size() && !test; i++){
if(array1.get(i) == (array.get(i))){
test = true;
}
}
return test;
}
except even when all the arrayLists numbers match the other arrayLists numbers, it returns false.
You don't need to overwrite the equals method, as there is one already provided for lists that does exactly what you need.
If you insist of writing it yourself there is a simple error in your code.
Because you initialize test to be false, "&& !test" lets your loop exist right at the start.
The correct version would be:
public boolean equals(){
if(array.size()!=array1.size) return false; // test for different length
for(int i = 0; i < array1.size(); i++){
if(!array1.get(i).equals(array.get(i))){
return false;
}
}
return true;
}
double equals (==) is dangerous. You are actually returning objects in your code up there, so you should definitely use equals() instead
Think that you are only iterating one array. Think what can go wrong there. Also take a look at your control statement.
If you carefully follow the flux of your code you quickly will realize why is false.
You should just 'reverse' your method. Assume the arrays are equal first. It should then check on each iteration if the element differs. If the element differs, then set a "not equal" flag. In pseudo-codee
boolean different = false;
for (each element of array 1) {
if (element != element of array 2) different = true
break;
}
You'll need to change your code to this:
public boolean equals(){
if (array1.size() != array.size()) return false;
for(int i = 0; i < array1.size(); i++){
if(!array1.get(i).equals(array.get(i))){
return false;
}
}
return true;
}
First off, you have to start with test being true and return false if you find something that isn't equal, because this clearly shows that the ArrayLists are not equal. You actually don't need the test variable at all, so I took it out. Just return false if you find something that isn't equal. If you don't find something that isn't equal, it will never return false and will just return true at the end. Second, you have to use the equals() method, because ArrayLists use the Integer class, not the int primitive so == will check if they are the same object, not if they are the same number. Lastly, to deal with comparing arrays of different sizes, you should compare their size and return false if they are not the same size, since there is no way they can be equal.

Java recursive binary tree

Welcome!
I have a recursive public static method named less that takes a tree node (an original binary tree, not really a search tree) and a int parameter that returns if all the values in the tree are less than the integer. So, I would use a public class TN { public int value; public TN left, right; public TN(int v, TN l, TN r) {value = v; left = l; right = r;} }
So, my method would look like this:
public static boolean less(TN s, int toFind){
if (s == null)
return true;
else{
if(s.value <= toFind)
return less(s.left, toFind) && less(s.right, toFind); // right here do I return true? or do I have to somehow recall recursively
else
return false;
}
I was wondering if that was right or am I missing something??? Do I have to return true and false??
There are much more elegant, OO ways to write this. My recommendation would be to make less() a non-static member function of the TN class. That way, if the tree's root node is called root, you just call root.less(). Each call to less() will then call left.less() and right.less().
Since you posted example code that wouldn't even compile, I'm wondering if you're using an IDE, or even tried to compile your class using javac. I strongly recommend getting Eclipse, Netbeans, or another IDE if you're new to Java.
return less(s, toFind);
should be:
return less(s.left, toFind) && less(s.right, toFind);
I don't know why the function is static.
As mentioned before, your first part should just be:
if (s == null) return true;
(EDIT: This will let you get a true result when all nodes meet the condition. You have an == in there that should be a <).
EDIT: Ok, you've got a lot of problems than just those I mentioned. You need to logically step through your code.
You need to traverse your tree, so you'll need to call your function on your children nodes. Next, you need to return true as your default result. That way, when you reach a number greater than what you're looking for, you can return false immediately without traversing any of the children. I hope I've helped you enough with the logic for you to get through the rest of it yourself.
First, if (s = null) should be if (s == null) as you are doing a comparison, not setting the value of s to null.
The statement return less(null, toFind); keeps calling your method - you'll overflow your stack.
Notice how there's no way that your function could ever return true because every time you terminate the recursion, you're returning false? And the problem is in your first check. You say that "all the values in the tree are less than the integer." Well, in an empty tree, all the values (of which there are none) are indeed less than any integer, so you should return true in that case.
Also, while you say "less than", you're comparing for equality, so you're actually checking whether all the values are equal to the integer, not less than it.

Categories