问题
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;
}
回答1:
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.
回答2:
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);
}
}
}
回答3:
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.
来源:https://stackoverflow.com/questions/36120004/implementing-an-equals-method-recursively