Java 递归实现equals方法

Java 递归实现equals方法,java,recursion,equals,Java,Recursion,Equals,基本上,我需要比较两个数组,并检查它们在相同位置是否有相同的值(当然是递归的)。我的当前代码出错:数组超出索引异常:20 我现在拥有的代码如下所示: private boolean equalsHelper(int[] first, int[] second, int iStart, int iEnd){ if (first[iStart] == second[iStart]){ if (equalsHelper(first,second,(iStart+1),i

基本上,我需要比较两个数组,并检查它们在相同位置是否有相同的值(当然是递归的)。我的当前代码出错:数组超出索引异常:20

我现在拥有的代码如下所示:

    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;
}

撇开递归是否是正确的解决方案的问题不谈(其实不是,这里的迭代很简单,而且会执行得更好),问题是直到递归调用之后才检查终止条件(
iStart==iEnd

任何递归算法都必须a)检查是否适合继续递归,b)在检查之后执行递归调用。如果没有包含第一步,或者没有按顺序执行这些步骤,将导致无限递归,直到出现错误为止(
StackOverflowerError
如果没有先发生任何其他情况)


在递归调用之前确实有一个条件检查,但它是为了方法的整体目的,而不是为了结束递归。您还有一个结束递归的条件检查,但它是在递归调用之后完成的。解决方案是交换它们的顺序——将
if(iStart==iEnd)
块移到
if(first[iStart]==second[iStart])
块之前。

递归是一种强大的编程技术,但在Java语言中有一些缺点。如果java中的方法在返回之前递归调用自身的次数过多,则会导致StackOverflower错误。在这种情况下,比较两个数组的相等性几乎可以保证做到这一点

Scala等其他语言允许您编写递归函数,这些函数针对递归(尾部递归)进行了优化,并在恒定的堆栈空间中执行

也就是说,您应该考虑递归是否真的是正确的解决方案。它既不优化解决方案,也不增加代码的清晰度


注意:如果您只想比较Java中的两个数组,那么
Java.util.Arrays
已经介绍过了。

您只需要在代码开始时设置停止条件。如果
iStart
开头为0,并且
iEnd
为数组长度-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;
}
如果要使用数组长度作为
iEnd
的输入,只需稍微更改代码即可

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;
}
由于性能被提到了几次,我将对它说几句话。 堆栈包含有关局部变量和函数调用的信息。因此,每个recursiv调用都会将这些信息保存在堆栈上,这将导致在大量输入上出现堆栈溢出,因为堆栈只有有限的空间。与循环相比,它的执行速度也较慢,因为有更多的汇编命令

这可以通过使用尾部递归函数来避免。 尾部递归调用意味着递归调用必须是在方法中执行的最后一条语句。编译器将把它转换成一个循环。这会更快,并且在堆栈上使用更少的空间

equals方法的尾部递归版本如下所示:

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);
        }
    }
}

你应该在某个时候检查数组的
长度
。这是家庭作业吗(你不能使用?我不认为这是递归的-当然。你把它复杂化了。为什么不先检查两个数组的长度是否不同。如果不是,它们就不相等-“当然”。如果是,就使用for循环,在每个索引上循环以比较相似的索引。如果你找到一个不相等的索引'不匹配-它们不相等。如果完成对所有元素的传递-它们相等。我不能。赋值需要递归解决方案。